What is a distributive conditional type?
When a conditional type is applied to a naked type parameter that is a union, it runs once per union member and joins the results. IsString<string | number> becomes IsString<string> | IsString<number>. Wrapping in [T] turns this off.
Explain it simply
A teacher checking a pile of answer sheets marks each one separately and then adds up the marks. A distributive conditional type does the same: it takes each member of a union on its own, applies the question, and combines the answers into a new union.
That is exactly how Exclude works: T extends U ? never : T is run on every member, and members that match disappear because they become never. If you do not want the splitting, wrap both sides in square brackets.
Example
type ToArray<T> = T extends any ? T[] : never;
type A = ToArray<string | number>;
// string[] | number[] (distributed)
type ToArrayNoDist<T> = [T] extends [any] ? T[] : never;
type B = ToArrayNoDist<string | number>;
// (string | number)[] (not distributed)
// Exclude relies on distribution
type MyExclude<T, U> = T extends U ? never : T;
type C = MyExclude<"a" | "b" | "c", "a">; // "b" | "c"
// never in, never out
type D = ToArray<never>; // neverWhat to say in the interview
"Conditional types distribute over a union when the checked type is a bare type parameter, evaluating per member. That is why Exclude and Extract work on unions. To compare the union as a whole I wrap it, [T] extends [U], which disables distribution."
Common mistakes
- Forgetting that never distributes to never, so a conditional type on never returns never.