Zagadnienie 12 z 12
Dokładna równość
Każdy test na tej stronie sprawdza dokładną tożsamość typów, a nie przypisywalność. Ten wybór sprawia, że odpowiedź może być *użyteczna* i mimo to nie przejść — a zrozumienie tego odróżnia walkę ze sprawdzarką od jej czytania.
- Wyrażenie
A extends B ? true : false - Rozwija się do
true - Wyrażenie
B extends A ? true : false - Rozwija się do
true - Wyrażenie
Equal<A, B> - Rozwija się do
false
Przypisywalność w obie strony nadal nie oznacza równości w tym teście. Przecięcie zachowuje inną reprezentację.
Definicja typu
type A = { a: string } & { b: number }
type B = { a: string; b: number }
type Equal<X, Y> =
(<T>() => T extends X ? 1 : 2) extends
(<T>() => T extends Y ? 1 : 2) ? true : falseDlaczego extends nie wystarcza
type Inter = { a: string } & { b: number } type Flat = { a: string; b: number } type OneWay = Inter extends Flat ? true : false // true type Other = Flat extends Inter ? true : false // true // Mutually assignable — yet they are not the same type.
Wzajemna przypisywalność jest słabsza niż tożsamość. Przecięcie i spłaszczony obiekt przyjmują się nawzajem, ale różnią się strukturalnie — a sprawdzarka oparta na extends uznałaby niedokończoną odpowiedź za poprawną.
Sztuczka z Equal
type Equal<X, Y> = (<T>() => T extends X ? 1 : 2) extends (<T>() => T extends Y ? 1 : 2) ? true : false
Dwa odroczone warunki są wzajemnie przypisywalne tylko wtedy, gdy kompilator rozwiązuje je identycznie — a robi to wyłącznie dla naprawdę identycznych typów. To wewnętrzny szczegół implementacji, a nie udokumentowana funkcja, i najbliższa rzecz do równości typów, jaką TypeScript udostępnia.
Spłaszczanie przecięcia
type Prettify<T> = { [K in keyof T]: T[K] } & {} type Fixed = Prettify<{ a: string } & { b: number }> // { a: string; b: number } — now Equal passes
Mapowanie po zebranych kluczach tworzy świeży typ obiektowy. Końcowe & {} zmusza TypeScript do faktycznego wyliczenia mapowania zamiast trzymania go leniwie — dlatego ten idiom wygląda jak literówka, a nią nie jest.
Najczęstsza błędna odpowiedź
// Intent: does this tuple contain exactly `true`? type Includes<T extends unknown[], U> = U extends T[number] ? true : false Includes<[boolean], true> // true — but the tuple holds boolean, not true
extends pyta, czy true mieści się w boolean — i mieści. Przynależność to nie przypisywalność, a gdy zadanie mówi „dokładnie”, extends jest złym narzędziem.
Ćwiczenie
Odpowiedz true tylko wtedy, gdy obie strony to ten sam typ — przecięcie nie jest płaskim obiektem.
Spróbuj
1Flatten<{ a: 1 } & { b: 2 }>—→ { a: 1; b: 2 }
Do zapamiętania
Przypisywalne to nie równe. Gdy test odrzuca odpowiedź, która wyraźnie działa, winowajcą jest zwykle przecięcie, którego nikt nie spłaszczył.

