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.