Input-dependent API results
A function's return shape changes according to whether its generic input is a string or number.
TypeScript · Function
Conditional types choose one of two types by testing whether one type is assignable to another. They can map generic inputs to precise outputs, distribute over unions, and infer types from matched structures.
A conditional type tests assignability with extends and chooses one of two types. If the checked type is assignable to the tested type, TypeScript selects the true branch; otherwise it selects the false branch. When generic information is insufficient, evaluation can be deferred, and a naked type parameter distributes the condition across union members.
T extends U ? X : Y| Name | Type | Description |
|---|---|---|
T | type | The type being tested against the condition. |
U | type | The type relationship target used by extends. |
X | type | The type selected when T is assignable to U. |
Y | type | The type selected when T is not assignable to U. |
The conditional type resolves to either the true branch type or the false branch type, or remains deferred until enough type information is available.
infer captures a type discovered while matching the checked type against a structural pattern.[T] extends [U], when you need to test the union as a whole.type IdLabel = { id: number };
type NameLabel = { name: string };
type Label<T extends number | string> =
T extends number ? IdLabel : NameLabel;
function createLabel<T extends number | string>(value: T): Label<T> {
return (typeof value === "number"
? { id: value }
: { name: value }) as Label<T>;
}
const byId = createLabel(42);
const byName = createLabel("Ada");The type-level condition selects the result shape from the argument type, while the runtime branch constructs the corresponding value.
A function's return shape changes according to whether its generic input is a string or number.
A type transformation should retain only union members matching a structural or primitive constraint.
A utility type needs to extract a return type, tuple element, or other component from a matched type pattern.
A deeply nested type must be unwrapped or transformed recursively.
A conditional type has the form T extends U ? X : Y. It resolves to X when T is assignable to U, and to Y otherwise; if generic information is not sufficient, evaluation is deferred.
Follow-up: How can a conditional type process a union? A distributive conditional type applies the test independently to each member when the checked type is a naked type parameter.
Conditional types let a generic API express different output types for different input types. For example, a number input can map to an ID-shaped result while a string input maps to a name-shaped result, reducing overloads.
Follow-up: What limitation remains in the function body? The implementation must still satisfy runtime checking; the conditional return type does not itself execute or validate JavaScript behavior.
infer do inside a conditional type?infer introduces a type variable inside the extends pattern so TypeScript can extract part of a matching type. A common use is inferring a function's return type or an element from a tuple.
Follow-up: How can recursive type transformations use this feature? A conditional type can refer to itself in its branches to recursively unwrap or transform nested structures.
inferDistributive conditional typesUtility TypesTypeScript 2.8Recursive Conditional Types