Przejdź do treści
webtype.org#220 rebuild-exclude · par 3

Nr 220 · 28 lipca 2026 · Średnia

Odtwórz Exclude

Zaimplementuj `MyExclude<T, U>`, aby usuwał z unii `T` każdy element przypisywalny do `U`. To jedna linia — subtelność polega na tym, dlaczego ta linia w ogóle działa.

01

Spróbuj rozwiązać samodzielnie

Par 3

Zagadka

rebuild-exclude.ts
Podejście 1 z 3Jeszcze nie sprawdzone

Zastąp ??? — rozwiązanie sprawdzamy przypadkami poniżej. Tab wcina; naciśnij Escape, a potem Tab, by wyjść fokusem.

Testy

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

Jak oceniamy test Dokładna równość typów, nie przypisywalność — przecięcie to nie to samo co spłaszczony obiekt.

Jak poszło innym

Tę zagadkę rozwiązało jak dotąd mniej niż 5 osób. Rozkład pojawi się, gdy próbka będzie na tyle duża, by coś znaczyć.

Archiwum
02

Rozwiązanie z komentarzem

Opublikowano 29 lipca 2026

Rozwiązanie

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

Najczęstsza błędna odpowiedź

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

Owinięcie `T` w krotkę wyłącza dystrybucję, więc cała unia porównywana jest naraz. `["a" | "b" | "c"] extends ["a"]` jest fałszem i cała unia wraca nieprzefiltrowana.

Linia po linii

  1. T extends U

    `T` jest tu *nagie* — stoi samo po sprawdzanej stronie, nie owinięte w krotkę, tablicę ani obiekt. To dokładnie ten warunek uruchamia dystrybucję po unii.

  2. ? never : T

    Każdy element albo staje się `never`, albo przeżywa jako on sam. Złączenie wyników automatycznie usuwa `never`, bo `never` jest elementem neutralnym unii.

Do zapamiętania

Dystrybucja to różnica między pytaniem o unię a pytaniem o każdy jej element. `[T] extends [U]` to przełącznik, który ją wyłącza.