Concept 3 of 12
keyof and indexed access
These two operators are how you take an object type apart. `keyof` gets you the keys, indexed access gets you a value type back. Almost every useful transformation in this track is those two combined with something that iterates.
keyof gives a union, not a list
interface User { id: number; name: string } type Keys = keyof User // 'id' | 'name' type Values = User[keyof User] // number | string
The result is a union of literal key types, in no particular order. There is no way to ask for "the first key" — order is not part of what an object type guarantees, and anything relying on it would be relying on an implementation detail.
Indexing with a union distributes
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
Indexing with a union of keys yields the union of the corresponding value types. `T[number]` on an array or tuple is the same idea and is how you turn a tuple into a union in one step.
The common wrong answer
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
Postfix `[]` binds tighter than `keyof`, so this asks for the keys of an array of users rather than the values of a user. The result is a large union of array method names, which then fails somewhere far from the actual error.
Takeaway
`keyof T` opens an object up and `T[K]` reads out of it. Reach for these before writing a recursive type — a surprising number of problems need nothing more.