Wzorce
Jak zamienić `{ a: string } & { b: number }` w `{ a: string; b: number }`, by podpowiedzi były czytelne, a testy równości przechodziły?
Homomorficzne mapowanie przechodzi każdy klucz raz i odbudowuje jeden obiekt. Modyfikatory przeżywają; przecięcie nie.
Przepis
type Prettify<T> = { [K in keyof T]: T[K] } type Base = { a: string } type Extra = { b?: number; readonly c: boolean } type Merged = Prettify<Base & Extra>
Build to kompiluje i sprawdza każdy wynik poniżej.
Jak to działa
- 01
type Prettify<T> = { [K in keyof T]: T[K] }
Wygląda, jakby nic nie robiło, i dla zwykłego obiektu tak jest. Dostawszy przecięcie, przechodzi unię obu zbiorów kluczy i emituje jeden obiekt zawierający wszystkie.
Co dostajesz
Merged
→{ a: string; b?: number | undefined; readonly c: boolean; }Prettify<{ a: 1 } & { b: 2 }>→{ a: 1; b: 2; }Jeden obiekt tam, gdzie były dwa. Nic w przypisywalności się nie zmieniło — tylko kształt, a to jego porównuje `Equal`.
Prettify<{ a: 1 }> extends { a: 1 } ? true : false→true
Gdzie to zawodzi
Spłaszcza jeden poziom. Przecięcie zagnieżdżone we właściwości pozostaje przecięciem, a rekurencyjne zastosowanie tego rozwinie też każdy napotkany typ wbudowany — łącznie z `Date` i `Promise`, czego rzadko ktokolwiek chciał.
Wniosek
Przecięcia składają typ obiektu; homomorficzne mapowanie go wykańcza. Złożenie bez wykończenia to najczęstszy powód, dla którego poprawnie wyglądający typ oblewa test równości.