Zagadnienie 4 z 12
Typy mapowane
Typ mapowany to pętla po unii kluczy, która buduje obiekt. Partial, Required, Readonly i Pick to po jednej linii tego zapisu — a gdy kształt stanie się znajomy, napiszesz każdy z nich z pamięci.
- Wyrażenie
Flags<"read"> - Rozwija się do
{ read: boolean } - Wyrażenie
Flags<"read" | "write"> - Rozwija się do
{ read: boolean; write: boolean }
Każdy element unii kluczy staje się właściwością. Reguła wartości stosuje się do każdego klucza.
Definicja typu
type Flags<K extends string> = { [P in K]: boolean }Kształt
type MyPartial<T> = { [K in keyof T]?: T[K] } // ^^^^^^^^^^^^^^ ^ ^^^^ // key set | value type // modifier
Czytaj to tak: dla każdego K w tym zbiorze kluczy stwórz właściwość o nazwie K i typie z tego wyrażenia. Zbiór kluczy to dowolna unia string, number lub symbol — zwykle keyof T, czasem parametr, sporadycznie coś wyliczonego.
Modyfikatory dodają i odejmują
type Optional<T> = { [K in keyof T]+?: T[K] } // add ? type Required<T> = { [K in keyof T]-?: T[K] } // remove ? type Frozen<T> = { readonly [K in keyof T]: T[K] } type Thawed<T> = { -readonly [K in keyof T]: T[K] }
Mapowanie po gołym keyof T jest *homomorficzne*, co znaczy, że istniejące modyfikatory ? i readonly są kopiowane automatycznie. Dlatego mapowanie tożsamościowe niczego nie zmienia i dlatego usunięcie modyfikatora wymaga jawnego minusa.
Zmiana nazw kluczy przez as
type Getters<T> = { [K in keyof T as `get${Capitalize<K & string>}`]: () => T[K] } // A key renamed to never disappears — this is how you filter. type OnlyStrings<T> = { [K in keyof T as T[K] extends string ? K : never]: T[K] }
Klauzula as przepisuje każdy klucz w trakcie mapowania. Klucz przepisany na never nie może istnieć, więc właściwość znika — i to jedyny sposób usunięcia właściwości z typu obiektowego.
Najczęstsza błędna odpowiedź
// Intent: keep only the string-valued properties. type OnlyStrings<T> = { [K in keyof T]: T[K] extends string ? T[K] : never } // Every key survives; the rejected ones just hold never. // { name: string; age: never }
Filtrowanie po stronie wartości nie usuwa klucza, tylko go opróżnia. Filtruje się w klauzuli klucza przez as ... : never, a pomylenie tych miejsc daje typ, który wygląda na przefiltrowany i niczego nie egzekwuje.
Ćwiczenie
Zamień każdą właściwość T na string, zachowując te same klucze.
Spróbuj
1type User = { id: number; admin: boolean }Stringify<User>—→ { id: string; admin: string }
Do zapamiętania
{ [K in Klucze]: Wartość } to pętla. Modyfikatory doczepiają się do właściwości, as przepisuje klucz, a never jako klucz sprawia, że rzeczy znikają.
Ćwiczone w
- #212Odtwórz PickPar 2
- #219Odtwórz PartialPar 2
- #226Odtwórz ReadonlyPar 2
- #235WybierzPoTypiePar 3
- #236GetteryPar 3
- #241Odtwórz RequiredPar 2
- #242ScalPar 3
- #246WpisyPar 4
- #247Pomiń po typiePar 3
- #249Opcjonalne, ale tylko tePar 3
- #256OdwróćPar 3
- #257Krotka na obiektPar 3
- #258Które klucze są opcjonalnePar 4
- #263Z wpisówPar 3
- #270Wszystkie wartości obiektuPar 3
- #274Zastąp klucze uniiPar 4
- #278Klucze w camelCasePar 3

