Skip to content
TypeScript ts advanced-types 4 min read

The keyof Operator

The keyof operator takes an object type and produces a union of its keys as string (or number/symbol) literal types. It is the foundation of type-safe property access in TypeScript: instead of accepting any string, you can constrain a value to only the keys that actually exist on a type. Combined with generics and indexed access, keyof powers helpers like Object.keys, property getters, and most of the standard utility types. This page covers the basic operator, how it behaves with index signatures, and the canonical type-safe getter pattern.

Basic usage

Apply keyof to any object type and you get back a union of its property names as literal types. The result updates automatically when the source type changes, so it never drifts out of sync.

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

type UserKey = keyof User; // "id" | "name" | "email"

const key: UserKey = "name"; // ✅
// const bad: UserKey = "age"; // ❌ Error: not assignable to "id" | "name" | "email"

UserKey is exactly the three keys of User. Add a property to the interface and the union widens with no extra work, which is why keyof is preferred over hand-written string unions that you have to maintain by hand.

keyof with index signatures

When a type uses an index signature, keyof returns the index signature’s key type rather than a finite union. A string index signature yields string | number (because numeric keys are coerced to strings at runtime), and a number index signature yields number.

interface StringMap {
  [key: string]: unknown;
}
type StringMapKeys = keyof StringMap; // string | number

interface NumberMap {
  [key: number]: unknown;
}
type NumberMapKeys = keyof NumberMap; // number
Source typekeyof result
{ a: 1; b: 2 }"a" | "b"
{ [k: string]: V }string | number
{ [k: number]: V }number
string (primitive)union of String.prototype members
anystring | number | symbol

The type-safe getter pattern

The most common use of keyof is constraining a generic parameter to the keys of another type. This makes a generic getProperty function reject invalid keys and infer the precise return type via indexed access.

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

const user = { id: 1, name: "Ada", active: true };

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

Because K extends keyof T, only real keys are allowed, and the return type T[K] is the exact type of that property — string for "name", boolean for "active". This single signature replaces dozens of overloads.

keyof operates on types, not values. To get the keys of a runtime object you combine it with typeof: keyof typeof someObject.

keyof on a value via typeof

You often have a concrete object and want its keys as a type. Use typeof to lift the value into a type, then apply keyof to that.

const config = {
  host: "localhost",
  port: 5432,
  ssl: false,
} as const;

type ConfigKey = keyof typeof config; // "host" | "port" | "ssl"

function readConfig(key: ConfigKey) {
  return config[key];
}

Here typeof config produces the object type, and keyof extracts its keys. The as const is optional but keeps the value’s literal types intact for the property values.

keyof with mapped types

keyof is the engine behind mapped types, which iterate in keyof T to transform every property. This is how Partial, Readonly, and friends are defined.

type Nullable<T> = {
  [K in keyof T]: T[K] | null;
};

type NullableUser = Nullable<User>;
// { id: number | null; name: string | null; email: string | null }

The [K in keyof T] clause walks each key K, and T[K] | null widens each value to allow null. Every property is preserved with its original key.

Best Practices

  • Derive key unions with keyof instead of duplicating string literals by hand.
  • Constrain generic key parameters with K extends keyof T for compile-time safety.
  • Return T[K] (indexed access) from generic getters to keep precise value types.
  • Remember that keyof on a string index signature includes number as well as string.
  • Use keyof typeof value to derive key types from concrete runtime objects.
  • Pair keyof with as const when you need literal key and value types preserved.
Last updated June 29, 2026
Was this helpful?