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.