1. Usage 1: Generic constraints (Constraint)
- Limit the "value range" of generics
1️⃣ The most basic example
ts
function getLength<T extends { length: number }>(value: T) {
return value.length;
}- ✅ string / array
- ❌ number
📌 extends = T must satisfy a certain structure
2️⃣ Constraint key (UHF)
ts
function getValue<T, K extends keyof T>(obj: T, key: K) {
return obj[key];
}Here:
Kcan only be the key ofT- Otherwise, an error will be reported directly
3️⃣ Constraint function type
ts
type Fn<T extends (...args: any[]) => any> = T;Common writing methods for React/Vue hooks types.
2. Usage 2: Conditional Types
- Return different types like ternary expressions
1️⃣ Basic grammar
ts
T extends U ? X : Y2️⃣ Basic example
ts
type IsString<T> = T extends string ? true : false;
type A = IsString<"a">; // true
type B = IsString<123>; // false3️⃣ Common built-in tool types
Exclude
ts
type MyExclude<T, U> = T extends U ? never : T;Extract
ts
type MyExtract<T, U> = T extends U ? T : never;4️⃣ Determine function return value (actual combat)
ts
type Return<T> = T extends (...args: any[]) => infer R ? R : never;(This is how ReturnType works)
3. Usage 3: Distribution condition type (Distributive)
- Condition type + union type = automatic split calculation
📌 This is the most confusing part
1️⃣Look at an example
ts
type ToArray<T> = T extends any ? T[] : never;
type A = ToArray<string | number>;Calculation process:
ts
ToArray<string> | ToArray<number>;
// string[] | number[]2️⃣ Conditions for distribution to occur (remember this)
- Only dispatched if
Tis a "naked type parameter"
✅ Distribution:
ts
T extends U ? X : Y❌ Not distributed:
ts
[T] extends [U] ? X : Y3️⃣ Turn off distribution (very important)
ts
type NoDistribute<T> = [T] extends [string] ? true : false;
type A = NoDistribute<string | number>;
// false4. Comparative summary of three usages
| Usage | Writing | Occurrence time |
|---|---|---|
| Constraints | <T extends U> | Generic declaration |
| Condition | T extends U ? X : Y | Type calculation |
| Distribution | Condition + Union | Automatic |
5. How to use extends for real tool types?
1️⃣ NonNullable<T>
ts
type NonNullable<T> = T extends null | undefined ? never : T;2️⃣ Parameters<T>
ts
type Params<T> = T extends (...args: infer P) => any ? P : never;3️⃣ Awaited<T>
ts
type Awaited<T> = T extends Promise<infer R> ? Awaited<R> : T;6. Front-end real scene
1️⃣ Determination of form value type
ts
type FieldValue<T> = T extends HTMLInputElement
? string
: T extends HTMLSelectElement
? string
: never;2️⃣ API status type
ts
type ApiResult<T> = T extends null
? { success: false }
: { success: true; data: T };7. 3 combos of must-ask questions in the interview (standard answers)
Q1: How many uses of extends in TS?
- 3 types: generic constraints/condition types/distribution condition types
Q2: When will distribution occur?
- When the left side of extends is a naked type parameter and it is a union type
Q3: How to turn off distribution?
- Wrap a layer with tuple
[T] extends [U]
8. The ultimate memory formula 🧠
- declaration-time constraint → constraint
- Judgment during calculation → condition
- United Demolition → Distribution