keyof in TypeScript
keyof takes a type and returns a union of its property names. That's it. One operator, but it unlocks some of the most useful patterns in TypeScript.
23 Apr 2024

keyof takes a type and returns a union of its property names. That's it. One operator, but it unlocks some of the most useful patterns in TypeScript.
interface User {
name: string;
age: number;
email: string;
}
type UserKeys = keyof User; // "name" | "age" | "email"
Why this matters
The real power shows up in generic functions. Say you want a function that reads a property from any object, but you want TypeScript to know the return type:
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
const user: User = { name: "Ehsan", age: 30, email: "ehsan@gazar.dev" };
const name = getProperty(user, "name"); // TypeScript knows this is a string
const age = getProperty(user, "age"); // TypeScript knows this is a number
getProperty(user, "foo"); // Compile error — "foo" is not a key of User
Without keyof, you'd use string as the key type and lose all type information about the return value.
Constraining function parameters
function processUser(user: { [key in keyof User]: any }) {}
This ensures the function only accepts objects that have exactly the same keys as User, even if the value types differ.
The trade-off
keyof makes your types more precise. That's the benefit — fewer runtime surprises, better autocomplete, safer refactoring.
The cost: your type signatures become harder to read. Generic functions with multiple keyof constraints can look intimidating. If your teammates aren't comfortable with advanced TypeScript, simpler (less type-safe) approaches might be the better choice for your team.
I use keyof heavily in utility types and library code. In application code, I keep it simple unless type safety demands otherwise.