Conditional types enable if/else logic at the type level: T extends U ? X : Y. They distribute over union types when T is a naked type parameter. With infer, they extract types from complex type positions. Built-in utility types (NonNullable, ReturnType, Parameters, Awaited) are all implemented with conditional types. Deferred resolution means conditional types are evaluated lazily — essential for recursive types.
Recursive type unwrapping with conditional types and infer.
Conditional types distribute over naked type parameters. type IsString<T> = T extends string ? true : false; IsString<string | number> = true | false (not false). Wrap in [] to prevent distribution: [T] extends [string].
string | never = string. never in a union gets absorbed. This property is what makes conditional type filtering work — return never for members you want removed from the union.
type FirstParam<T> = T extends (first: infer F, ...rest: any[]) => any ? F : never. infer can appear in any covariant position to extract that type.
Sign in to share your feedback and join the discussion.