Conditional Types
12 min read
Conditional Types
A conditional type selects one of two types based on a type-level condition: T extends U ? TrueType : FalseType. If T is assignable to U, the result is TrueType; otherwise it is FalseType.
ts
type IsString<T> = T extends string ? true : false;
type A = IsString<"hello">; // true
type B = IsString<42>; // false
type C = IsString<string>; // true
// Conditional types distribute over union members
type NonNullable<T> = T extends null | undefined ? never : T;
type D = NonNullable<string | null | undefined>; // stringThe `infer` keyword
infer declares a type variable inside the extends clause that TypeScript fills in when the condition matches. This is how ReturnType and Awaited are implemented.
ts
// Extract the return type of any function
type ReturnType<T extends (...args: any[]) => any> =
T extends (...args: any[]) => infer R ? R : never;
// Extract the element type from an array
type ElementType<T> = T extends (infer E)[] ? E : never;
type E = ElementType<string[]>; // string
type F = ElementType<number[]>; // number
// Unwrap a Promise
type Awaited<T> = T extends Promise<infer V> ? Awaited<V> : T;
type G = Awaited<Promise<Promise<number>>>; // numberConditional types are evaluated lazily when the type parameter is generic. When the type parameter is a concrete (non-generic) type, distribution happens immediately. This distinction matters when writing higher-order generic utilities.
Ready to test yourself?
Practice TypeScript— quiz & coding exercises