Skip to content
webtype.org#220 rebuild-exclude · par 3

No. 220 · July 28, 2026 · Moderate

Rebuild Exclude

Implement `MyExclude<T, U>` so it removes from the union `T` every member assignable to `U`. It is one line — the subtlety is why that line works at all.

01

Try the puzzle yourself

Par 3

Puzzle

rebuild-exclude.ts
Stroke 1 of 3Not run yet

Replace ??? — your solution is checked against the cases below. Tab indents; press Escape then Tab to move focus out.

Checks

4
  • MyExclude<'a' | 'b' | 'c', 'a'>
    'b' | 'c'
  • MyExclude<string | number, number>
    string
  • MyExclude<'a', 'a'>
    never
  • MyExclude<'a' | 'b', 'c'>
    'a' | 'b'

How a check is judged Exact type equality, not assignability — an intersection is not the same as the flattened object.

How everyone did

Fewer than 5 people have solved this one so far. The distribution appears once there is enough of a sample to mean anything.

Archive
02

Annotated solution

Published July 29, 2026

The solution

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

The common wrong answer

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

Wrapping `T` in a tuple switches distribution off, so the whole union is compared at once. `["a" | "b" | "c"] extends ["a"]` is false, and the entire union comes back unfiltered.

Line by line

  1. T extends U

    `T` here is *naked* — it appears alone on the checked side, not wrapped in a tuple, array or object. That is the exact condition that triggers distribution over a union.

  2. ? never : T

    Each member either becomes `never` or survives as itself. Unioning the results drops the `never`s automatically, because `never` is the identity element of union.

Takeaway

Distribution is the difference between asking a question about a union and asking it about each member. `[T] extends [U]` is the switch that turns it off.