TypeScript Keyof

The keyof operator turns the properties of a type into a union of string, number, or symbol literal types, letting you write functions that are safely constrained to an object's actual keys.

Turning Properties Into a Type

keyof is a type-level operator, not a runtime function. Given a type T, keyof T produces a union of every property name of T as a literal type. It's the compile-time counterpart to what Object.keys() gives you at runtime, except the compiler checks it for you.

Basic keyof

interface User {
  id: number;
  name: string;
  email: string;
  isActive: boolean;
}

type UserKeys = keyof User;
// "id" | "name" | "email" | "isActive"

const key: UserKeys = "name"; // OK
// const bad: UserKeys = "age"; // Error: not assignable

console.log(key);

Safe Property Access With Generics

The most common pattern pairs keyof with a generic constraint: K extends keyof T. This lets a function accept any key of an object while TypeScript infers the exact return type for that key, rejecting typos at compile time.

Generic getProperty

function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}

const user = { id: 1, name: "Ada", email: "ada@example.com", isActive: true };

const name = getProperty(user, "name");     // string
const active = getProperty(user, "isActive"); // boolean
// getProperty(user, "age"); // Error: "age" is not a key of user

console.log(name, active);

keyof typeof for Object Literals

  • Building typed pick/omit helpers around arbitrary objects
  • Restricting form-field names to keys that actually exist on a model
  • Typing Redux-style selector maps keyed by state slice
  • Creating enum-like lookup tables with keyof typeof
  • Powering autocomplete for dynamic property lookups in editors

keyof typeof with a const object

const roleLevel = {
  admin: 3,
  editor: 2,
  viewer: 1,
} as const;

type Role = keyof typeof roleLevel; // "admin" | "editor" | "viewer"

function hasAccess(role: Role, required: number): boolean {
  return roleLevel[role] >= required;
}

console.log(hasAccess("editor", 2)); // true
ExpressionEvaluatedResult type
keyof Tcompile timeunion of literal key types
Object.keys(obj)runtimestring[] (always widened)
typeof objcompile timethe literal shape/type of a value
Note: Combine keyof with mapped types (in Part 3) and you can hand-roll your own Pick, Partial, or Record equivalents instead of relying only on the built-in utility types.
Note: If an interface mixes named properties with a string index signature, keyof collapses to string | number, and the named keys are no longer individually visible in the union.

Exercise: TypeScript Keyof

What does the `keyof` operator produce from an object type?