Suggest an editImprove this articleRefine the answer for “What is distributive behavior of union types?”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**Distributive behavior** means that when TypeScript applies a conditional type (`extends ? :`) to a union type through a naked type parameter, it automatically applies the expression to each member of the union separately and then combines the results back into a `union`. **Key point:** distributive behavior can be turned off by wrapping the type in a tuple - `[T] extends [U] ? ... : ...`.Shown above the full answer for quick recall.Answer (EN)Image## What **distributive behavior of union types** is **Distributive behavior** means that when TypeScript applies a **conditional type (**`extends ? :`**)** to a **union type**, it **automatically applies** the expression **to each member of the union** and then **combines the results back** into a `union`. --- ## Example 1. A simple illustration ```javascript type T = string | number; type Box<T> = T extends any ? { value: T } : never; ``` What happens: - TypeScript takes `string` - then `number` - applies the condition to each one - and combines the results back ```javascript type Result = Box<string | number>; // Expands as: // Box<string> | Box<number> // -> { value: string } | { value: number } ``` In short: `Box<string | number>` ≡ `{ value: string } | { value: number }`. --- ## Why this happens Because **in conditional types**, when the left side of `extends` is a **type parameter** (`T`), rather than a concrete type like `{}` or `unknown`, TypeScript **unfolds the union** and applies the condition **separately to each member**. > This is a special rule - "distributive conditional types". --- ## Example 2. Let's check non-distributive behavior If you wrap `T` in a "container", the distributive behavior **disappears**: ```javascript type Boxed<T> = [T] extends [any] ? { value: T } : never; type Result = Boxed<string | number>; // Now it does not distribute! // [string | number] does not extend [any] distributively // Result: { value: string | number } ``` The difference: | Expression | Result | |---|---| | `T extends any ? X<T> : never` | `X<string> \| X<number>` | | `[T] extends [any] ? X<T> : never` | `X<string \| number>` | The `[]` wrapper turns off distributive behavior. --- ## Example 3. A real case - extracting a subtype ```javascript type ExtractString<T> = T extends string ? T : never; type R = ExtractString<string | number | boolean>; // distributes as: // string -> string // number -> never // boolean -> never // combined: string | never | never -> string ``` In short: `ExtractString<string | number | boolean>` -> `string`. > This is how the built-in TypeScript utilities `Extract<>`, `Exclude<>`, `NonNullable<>`, and others work. --- ## Example 4. Usage in Exclude and Extract ```javascript type Exclude<T, U> = T extends U ? never : T; type R = Exclude<"a" | "b" | "c", "a" | "c">; // distributes as: // "a" extends "a"|"c" -> never // "b" extends "a"|"c" -> "b" // "c" extends "a"|"c" -> never // => "b" ``` > That's why `Exclude<"a" | "b" | "c", "a" | "c">` gives `"b"`. --- ## Example 5. Comparison with a "non-distributive" version ```javascript type NonDistributiveExclude<T, U> = [T] extends [U] ? never : T; type R = NonDistributiveExclude<"a" | "b" | "c", "a" | "c">; // [T] does not distribute // => ["a" | "b" | "c"] extends ["a" | "c"] -> false // => result = "a" | "b" | "c" ``` By wrapping `T` in a tuple `[]`, we **turn off distributive behavior** and force TypeScript to treat the union as a single whole. --- ## Example 6. An even clearer visualization Imagine a union as a set: ```javascript T = {A, B, C} T extends X ? Y : Z ``` TypeScript expands this as: ```javascript (A extends X ? Y : Z) | (B extends X ? Y : Z) | (C extends X ? Y : Z) ``` --- ## Key conclusions | Feature | Behavior | |---|---| | Works only in conditional types (`extends ? :`) | Yes | | Triggered when `T` is a naked type parameter | Yes | | Can be turned off by wrapping `T` in `[]` | Yes | | The basis of `Exclude`, `Extract`, `NonNullable` | Yes | | Applied element-wise to each member of the union | Yes | --- ## A simple summary > **Distributive behavior of union types** is > when TypeScript **applies a conditional type to each member of the union separately**, > and then **combines the results back into a union**. > > You can **turn this off** by wrapping the type in a tuple: `[T] extends [U] ? ... : ...`.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.