Hint
Distribute over union members; resolve to different types based on whether T satisfies U
Conditional types select a type based on a condition, similar to a ternary operator for types.
// Basic syntax: T extends U ? TypeIfTrue : TypeIfFalse
type IsString<T> = T extends string ? 'yes' : 'no';
type A = IsString<string>; // 'yes'
type B = IsString<number>; // 'no'
Distribution over union types — when T is a naked type parameter, conditional types distribute:
type ToArray<T> = T extends unknown ? T[] : never;
type StringOrNumberArray = ToArray<string | number>;
// Distributes: (string extends unknown ? string[] : never) | (number extends unknown ? number[] : never)
// = string[] | number[]
// Prevent distribution with []
type ToArrayNonDist<T> = [T] extends [unknown] ? T[] : never;
type NonDist = ToArrayNonDist<string | number>; // (string | number)[]
infer keyword — extract a type within a conditional:
// Extract the return type of a function
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;
type NumReturn = ReturnType<() => number>; // number
type VoidReturn = ReturnType<() => void>; // void
// Extract element type from an array
type ElementType<T> = T extends (infer E)[] ? E : never;
type Elem = ElementType<string[]>; // string
infer unlocks writing your own ReturnType, Parameters, PromiseType, and similar utilities.