Przejdź do treści
webtype.orgDwanaście zagadnień · 4/12

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.

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.

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