Mastering TypeScript's keyof Keyword
The keyof operator is essential for type-safe TypeScript code. Let's explore how it works.
What is keyof?
keyof produces a union of the keys of an object type.
interface User {
id: number;
name: string;
email: string;
}
type UserKeys = keyof User;
// Result: "id" | "name" | "email"
Basic Usage Example
function getProperty(obj: T, key: K): T[K] {
return obj[key];
}
const product = {
id: "1",
title: "Laptop",
price: 999
};
const title = getProperty(product, "title"); // Type: string
const price = getProperty(product, "price"); // Type: number
// ❌ Error
const invalid = getProperty(product, "invalid");
Real-World Example 1: Type-Safe Form Handler
interface FormData {
username: string;
email: string;
age: number;
}
type FormErrors = {
[K in keyof FormData]?: string;
};
class FormValidator {
private errors: FormErrors = {};
setError(field: K, message: string) {
this.errors[field] = message;
}
getError(field: K) {
return this.errors[field];
}
}
// Usage
const validator = new FormValidator();
validator.setError("username", "Too short"); // Type-safe!
Real-World Example 2: Event Emitter
interface Events {
login: { userId: string; timestamp: number };
logout: { userId: string };
error: { message: string; code: number };
}
class TypeSafeEventEmitter {
private listeners: {
[K in keyof Events]?: Array<(data: Events[K]) => void>;
} = {};
on(
event: K,
callback: (data: Events[K]) => void
) {
if (!this.listeners[event]) {
this.listeners[event] = [];
}
this.listeners[event]!.push(callback);
}
emit(event: K, data: Events[K]) {
this.listeners[event]?.forEach(cb => cb(data));
}
}
// Usage
const emitter = new TypeSafeEventEmitter();
emitter.on("login", (data) => {
// data is typed: { userId: string; timestamp: number }
console.log(`User ${data.userId} logged in`);
});
Advanced: Mapped Types with keyof
// Make all properties optional
type Partial = {
[K in keyof T]?: T[K];
};
// Make all readonly
type Readonly = {
readonly [K in keyof T]: T[K];
};
// Pick specific properties
type Pick = {
[P in K]: T[P];
};
Best Practices
1. Use with generics for flexibility 2. Constrain type parameters with K extends keyof T 3. Leverage index access T[K] 4. Document complex types
Conclusion
The keyof operator enables:
- Type-safe property access
- Dynamic key handling
- Better IDE autocomplete
- Fewer runtime errors
Master keyof for robust TypeScript!
Get More Like This
Want articles like this in your inbox?
Join developers and founders who get practical insights on frontend, SaaS, and building better products.
S
Written by Salman Izhar
Frontend Developer specializing in React, Next.js, and building high-converting web applications.
Learn More