type Name<T> = T extends Condition ? TrueType : FalseType;
example
type IsArray<T> = T extends any[] ? true : false;
type Test1 = IsArray<string[]>; // truetype Test2 = IsArray<number>; // false// Extracting element typestype ElementOf<T> = T extends (infer E)[] ? E : never;
type StrEl = ElementOf<string[]>; // stringtype NumEl = ElementOf<number[]>; // numbertype NoEl = ElementOf<boolean>; // never
output
// Conditional types act like type-level if/else
Note When a conditional type receives a union as T, it distributes — the condition is applied to each union member independently. To prevent distribution, wrap both sides in brackets: [T] extends [Condition].
type Result = T extends Pattern<infer U> ? U : Fallback;
example
// Extract the resolved type from a Promisetype UnwrapPromise<T> = T extends Promise<infer R> ? R : T;
type A = UnwrapPromise<Promise<string>>; // stringtype B = UnwrapPromise<number>; // number// Extract function first argumenttype FirstArg<T> = T extends (first: infer F, ...rest: any[]) => any ? F : never;
type FA = FirstArg<(name: string, age: number) => void>; // string// Extract array element typetype ArrayItem<T> = T extends readonly (infer E)[] ? E : never;
type Item = ArrayItem<readonly ["a", "b", "c"]>; // "a" | "b" | "c"
output
// infer declares a type variable that TypeScript figures out from context
Note infer can only be used inside the extends clause of a conditional type. It captures whatever type fits in that position. Multiple infer clauses in the same conditional are allowed. In union position, infer produces a union; in intersection position (like function params), it produces an intersection.