Conditional, Template Literal and Recursive Types
Conditional types are type-level if/else: `T extends U ? X : Y`. Combined with `infer`, distribution, template literals and recursion, they let you compute types from other types.
Key points
- 1
extendsin a conditional type is an assignability check.infer Xbinds a type variable from the match and is usable only in the true branch. - 2
A naked type parameter distributes over unions: each member is checked separately and the results are unioned. Wrap both sides in a tuple,
[T] extends [U], to turn this off. - 3
neveris the empty union, so a distributive conditional over never returns never.anyreturns the union of both branches. - 4
Several
infer Xcandidates in covariant positions combine into a union; in contravariant positions (function parameters) they combine into an intersection. That is how UnionToIntersection works. - 5
Template literal types multiply unions and can parse strings with
infer;infer N extends numberconverts numeric strings into number literals. - 6
Recursive conditional types in tail position run up to about 1,000 iterations (TS 4.5+); recursion inside spreads or other types hits the depth error far sooner. Use accumulators.
- 7
Inferring from an overloaded function uses its last signature, and a conditional return type on a generic function stays deferred, so returns need overloads or assertions.
Common traps
T extends never ? true : falsereturns never for never; use[T] extends [never].booleanistrue | false, so it splits in distributive conditionals and counts as a union.Mapping over a function type (for example in a naive DeepReadonly) turns it into
{}and drops its call signature.
Read the source
Test yourself on Conditional, Template Literal and Recursive Types
Ten questions, with the answer and explanation after each one.