Capítulo 9 de 36
T extends U ? TrueType : FalseType is an if-statement at the type level — mostly uninteresting on concrete types, but combined with generics it lets one type alias replace what would otherwise require an exponentially growing set of function overloads.
extends is assignable to the type on the right, the conditional resolves to the true branch; otherwise the false branch.type NameOrId<T extends number | string> = T extends number ? IdLabel : NameLabel, then write a single generic function createLabel<T extends number | string>(x: T): NameOrId<T>.type MessageOf<T> = T extends { message: unknown } ? T["message"] : never — inside the T extends {...} branch, TypeScript knows T has that shape and lets you index into it; types that don't match fall through to the false branch (never here, a sensible default for "doesn't apply").infer: introduces a new type variable inside the extends clause of a conditional type instead of manually destructuring with indexed access — type Flatten<T> = T extends Array<infer Item> ? Item : T extracts an array's element type declaratively. The same pattern extracts a function's return type: type GetReturnType<T> = T extends (...args: never[]) => infer R ? R : never.infer on an overloaded function type resolves against the last signature (presumed to be the most general/catch-all one) — TypeScript can't do overload resolution based on a hypothetical argument list here.Type extends any ? Type[] : never) automatically distributes over a union passed as that parameter — ToArray<string | number> becomes ToArray<string> | ToArray<number> = string[] | number[], not (string | number)[].extends in a tuple ([Type] extends [any] ? ... : ...) — this stops the union from being distributed member-by-member, so ToArrayNonDist<string | number> yields (string | number)[] as a single non-distributed result.type Flatten<Type> = Type extends Array<infer Item> ? Item : Type;
type Str = Flatten<string[]>; // string
type Num = Flatten<number>; // number (unchanged — not an array)
infer declaratively pulling an array's element type instead of a manual T[number] indexed-access lookup.type ToArray<Type> = Type extends any ? Type[] : never;
type Distributed = ToArray<string | number>; // string[] | number[]
type ToArrayNonDist<Type> = [Type] extends [any] ? Type[] : never;
type NotDistributed = ToArrayNonDist<string | number>; // (string | number)[]
| Pattern | Effect |
|---|---|
T extends U ? A : B | type-level if/else on assignability |
T extends { message: unknown } ? T["message"] : never | constrain-and-extract in one step; unmatched types fall to a safe default |
T extends Array<infer Item> ? Item : T | declarative extraction via infer, instead of manual indexed access |
Type extends any ? ... : ... (bare param) | distributes over unions |
[Type] extends [any] ? ... : ... | suppresses distribution |
infer is the idiomatic way to pull a piece out of a matched type inside a conditional — prefer it over manual indexed-access gymnastics when the shape you're extracting from is generic/unknown.extends in [...].infer frequently replaces.ReturnType<T>, Exclude<T, U>, and similar built-ins are implemented as conditional types with infer.