keyof, typeof & Lookup Types
keyof T produces a union of a type's property names, the typeof type operator derives a type from an existing value, and an indexed access (lookup) type T[K] reads the type of one of T's properties — together they let you write accessors that are checked against the real shape of your data.
Learn keyof, typeof & Lookup Types in our free TypeScript course — an interactive lesson with runnable examples, a practice exercise and a quick reference.
Part of the free TypeScript course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
Picture a filing cabinet (your object type). keyof is the printed list of drawer labels — every name you're allowed to ask for. The typeof type operator is taking a photograph of an existing cabinet and turning it into a reusable blueprint, so a new cabinet can be built to match. T[K] is opening one specific drawer to see what kind of thing lives in it. Ask for a label that isn't on the list and the clerk (the compiler) stops you before you waste time opening a drawer that doesn't exist.
1. keyof — Property Names as a Union
keyof T collects every property name of T into a union of string (and number/symbol) literal types. It's the type-level version of "what keys does this object have?" — and it stays in sync automatically when you add or rename a property:
2. The typeof Type Operator & T[K]
TypeScript reuses the typeof keyword in type positions to mean "the type of this value". It's perfect for deriving a type from a config object or a constant you already have. Pair it with an indexed access type T[K] to read individual property types, or T[keyof T] for the union of all value types:
3. keyof + Generics: a Type-Safe Getter
Put it all together: a generic getter constrains the key to a real property and uses the lookup type T[K] to return its exact type. This is the single most common real-world use of keyof — and it generalises to picking several keys at once:
🎯 Your Turn
Implement a small getter whose key would be constrained by keyof T , and log the runtime form of keyof typeof settings . Fill in the blanks and match the expected output.
Build a groupBy whose key is the runtime form of a keyof T constraint — bucket an array of objects by one property. Follow the outline, run it, and match the example output.
Practice quiz
What does keyof T produce?
- An array of the object's values
- The number of properties
- A union of T's property names
- A new object
Answer: A union of T's property names. keyof T is a union of the property names of T, e.g. keyof User is "id" | "name" | "email".
Is keyof a runtime feature like Object.keys?
- No, keyof is a type operator and is erased at compile time
- Yes, they are identical
- keyof runs only in strict mode
- keyof returns a Promise
Answer: No, keyof is a type operator and is erased at compile time. keyof is purely type-level; Object.keys is its runtime counterpart but they are not the same.
In a TYPE position, what does typeof x mean?
- A runtime string like 'object'
- The length of x
- Always any
- The inferred type of the value x
Answer: The inferred type of the value x. In a type position, typeof x is TypeScript's type operator: the inferred type of value x.
What does the indexed access (lookup) type T[K] read?
- The value at runtime
- The type of property K out of type T
- The number of keys
- A random property
Answer: The type of property K out of type T. T[K] reads the type of property K from T, e.g. User['name'] is string.
What is T[keyof T]?
- The union of all of T's property value types
- The first property's type
- Always string
- The keys as an array
Answer: The union of all of T's property value types. T[keyof T] is the union of every property value type in T.
Why constrain a key with <K extends keyof T> instead of typing it as string?
- string is faster
- It allows any key
- It forces the key to be a real property name, turning typos into compile errors
- It disables inference
Answer: It forces the key to be a real property name, turning typos into compile errors. Constraining to keyof T rejects typos like obj['naem'] and gives a precise T[K] return type.
How do you take the keys of a VALUE rather than a type?
- keyof value
- keyof typeof value
- value.keyof
- typeof keyof value
Answer: keyof typeof value. keyof operates on a type, so use keyof typeof value to first turn the value into a type.
What is keyof Record<string, number>?
- number
- string | number
- never
- string
Answer: string. Verified with tsc: keyof Record<string, number> is string, the record's key type.
For const Roles = { admin: "admin", user: "user" } as const, what is typeof Roles[keyof typeof Roles]?
- string
- "admin" | "user"
- Roles
- never
Answer: "admin" | "user". On an as const object this idiom produces the union of literal values "admin" | "user".
Why does writing { role: "admin" } without as const widen role to string?
- A bug in TypeScript
- Strings are always any
- Mutable object properties are widened from their literal type
- Because role is optional
Answer: Mutable object properties are widened from their literal type. Without as const the literal "admin" widens to string; as const keeps the literal type.