0Pricing
TypeScript Academy · Lesson

Distributive Conditional Types

Control how conditionals distribute over unions.

Distributive Conditional Types is a free TypeScript Academy lesson on CoddyKit — lesson 4 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the TypeScript Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

A Surprising Behavior

Conditional types have one special rule: when the checked type is a naked type parameter and you pass a union, the conditional distributes over each member separately, then unions the results.

This is the foundation of Exclude, Extract, and many utilities.

type ToArray<T> = T extends unknown ? T[] : never;

type A = ToArray<string | number>;
// string[] | number[]  (NOT (string | number)[])

What "Naked" Means

"Naked" means the type parameter appears by itself on the left of extends, not wrapped in another type. Distribution only happens for naked parameters.

type Naked<T> = T extends string ? "y" : "n";
// T is naked -> distributes over unions

Distribution Step by Step

For ToArray<string | number> the compiler evaluates each member:

  • ToArray<string> = string[]
  • ToArray<number> = number[]

Then unions them: string[] | number[].

type R = ToArray<boolean>;
// boolean is true | false, so:
// true[] | false[]

Filtering a Union

Distribution makes filtering easy. Map unwanted members to never; never disappears from a union, leaving only the kept members.

type Strings<T> = T extends string ? T : never;

type A = Strings<string | number | boolean>; // string

never Vanishes in Unions

A key fact: X | never simplifies to X. So when a distributed branch yields never, that member is effectively removed from the final union.

type A = string | never;        // string
type B = "a" | never | "b";     // "a" | "b"

Disabling Distribution

Sometimes you do not want distribution, for example when comparing a whole union as one unit. Wrap both sides in a one-element tuple: [T] extends [U]. Now T is no longer naked, so distribution is off.

type IsNever<T> = [T] extends [never] ? true : false;

type A = IsNever<never>;  // true
type B = IsNever<string>; // false

Why Wrapping Works

By putting [T] on the left, the checked type is a tuple, not the bare parameter. The special distribution rule no longer applies, so the union is tested as a whole.

type AllStrings<T> = [T] extends [string] ? true : false;

type A = AllStrings<"a" | "b">;     // true
type B = AllStrings<"a" | number>;  // false

Distributed vs Non-Distributed

Compare the two forms directly. The naked version checks each member; the wrapped version checks the union as one type.

type Distributed<T> = T extends string ? true : false;
type Wrapped<T> = [T] extends [string] ? true : false;

type A = Distributed<string | number>; // boolean (true | false)
type B = Wrapped<string | number>;     // false

Exclude Internals

The built-in Exclude<T, U> removes from T any member assignable to U. It is just a distributive conditional that maps matching members to never.

type MyExclude<T, U> = T extends U ? never : T;

type A = MyExclude<"a" | "b" | "c", "b">; // "a" | "c"

Extract Internals

Extract<T, U> is the mirror image: keep only the members assignable to U. Same distribution, opposite branches.

type MyExtract<T, U> = T extends U ? T : never;

type A = MyExtract<"a" | "b" | "c", "a" | "c">; // "a" | "c"

Practical Power

Distribution lets you transform every member of a union in one expression: build arrays of each, prefix every string, or filter by shape. Combined with [T] extends [U] for whole-union checks, you control exactly when distribution fires.

Notation: real TypeScript writes template literal types with backtick-delimited strings containing dollar-brace holes. In these snippets we show that pattern as Tpl<...>, listing each part in order; e.g. a backtick template matching the literal prefix then Rest appears as Tpl<'prefix', infer Rest>.

type Prefix<T extends string> = T extends unknown ? Tpl<'id_', T> : never;
// Tpl<'id_', T> is the template literal type joining 'id_' with each T

type A = Prefix<'a' | 'b'>; // 'id_a' | 'id_b'

Quick Check

Test your understanding of distributive conditionals.

Recap

Distributive conditional types are the engine behind union utilities.

  • A naked T extends U ? distributes over each union member.
  • Branches returning never filter members out.
  • [T] extends [U] disables distribution for whole-union checks.
  • Exclude and Extract are tiny distributive conditionals.

Course 22 next: arithmetic in the type system.

Frequently asked questions

Is the “Distributive Conditional Types” lesson free?

Yes — the full text of “Distributive Conditional Types” is free to read here on the web, and the TypeScript Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the TypeScript Academy course, upgrade to CoddyKit PRO.

What will I learn in “Distributive Conditional Types”?

Control how conditionals distribute over unions. You practise TypeScript Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start TypeScript Academy?

No prior experience is required. TypeScript Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 4 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “Distributive Conditional Types” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this TypeScript Academy lesson?

Yes. Every TypeScript Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. Types as a Computation Language
  2. Type-Level Conditionals
  3. Type-Level Recursion
  4. Distributive Conditional Types
← Back to TypeScript Academy