"Conditional types distribute over unions. Once you know this, several mysterious type errors stop being mysteries."
The rule
When a conditional type's checked type is a naked generic type parameter, and that parameter is a union, TypeScript distributes the conditional over each member of the union and unions the results. Symbolically: T extends X ? A : B applied to T = U1 | U2 becomes (U1 extends X ? A : B) | (U2 extends X ? A : B).
This is usually what you want. Sometimes it's not. The escape hatch: wrap the parameters in brackets — [T] extends [X] — which converts the comparison to a single-element tuple test and disables distribution.
When distribution is helpful
The classic use: type-level mapping over unions. type Wrap<T> = T extends unknown ? { value: T } : never. Applied to string | number, this distributes: Wrap<string> | Wrap<number> = { value: string } | { value: number }. Each member of the input becomes its own wrapped variant in the output.
Same pattern: Exclude<T, U> from the standard library is implemented as T extends U ? never : T — distribution is what makes it remove specific members from a union.
When distribution surprises
You expect a single result and get a union. Or you expect distribution and don't get it because the type parameter isn't naked (it's wrapped in another shape). The fix in both directions:
- To force distribution: keep the parameter naked at the conditional check site.
- To prevent distribution: wrap it in a tuple —
[T] extends [X].
The bracket trick comes up in many advanced TypeScript patterns. Once you know it exists, you'll spot it in library type definitions all the time.