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

Zagadnienie 3 z 12

keyof i dostęp indeksowany

Te dwa operatory pozwalają rozłożyć typ obiektowy. `keyof` daje klucze, dostęp indeksowany zwraca typ wartości. Prawie każde użyteczne przekształcenie w tej ścieżce to te dwa połączone z czymś, co iteruje.

keyof daje unię, nie listę

interface User { id: number; name: string }

type Keys = keyof User        // 'id' | 'name'
type Values = User[keyof User] // number | string

Wynikiem jest unia literałów kluczy, w nieokreślonej kolejności. Nie da się zapytać o „pierwszy klucz” — kolejność nie należy do tego, co gwarantuje typ obiektowy, a poleganie na niej byłoby poleganiem na szczególe implementacji.

Indeksowanie unią się rozdziela

interface User { id: number; name: string; admin: boolean }

type One = User['id']              // number
type Some = User['id' | 'name']    // number | string
type Every = User[keyof User]      // number | string | boolean

type Element = string[][number]    // string

Indeksowanie unią kluczy daje unię odpowiadających typów wartości. `T[number]` na tablicy lub krotce to ta sama idea i sposób, by w jednym kroku zamienić krotkę w unię.

Najczęstsza błędna odpowiedź

interface User { id: number; name: string }

// Intent: the value types of User.
type Values = keyof User[]
// Actually parses as keyof (User[]) — the keys of an ARRAY:
// 'length' | 'push' | 'pop' | ...

type Fixed = User[keyof User]  // number | string

Przyrostkowe `[]` wiąże silniej niż `keyof`, więc to pyta o klucze tablicy użytkowników, a nie o wartości użytkownika. Wynikiem jest wielka unia nazw metod tablicy, która psuje się potem daleko od prawdziwego błędu.

Do zapamiętania

`keyof T` otwiera obiekt, a `T[K]` z niego czyta. Sięgaj po nie, zanim napiszesz typ rekurencyjny — zaskakująco wiele problemów nie potrzebuje niczego więcej.