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

    ↑↓ ruch · ⏎ otwórz · esc zamknij

    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.

    Ćwiczenie

    Utwórz unię wszystkich typów wartości w `T`.

    Spróbuj

    1
    type User = { id: number; name: string }
    • Values<User>
      string | number

    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.