Mastering TypeScript's keyof: Type-Safe Dynamic Properties
TypeScriptAdvancedType Safety

Mastering TypeScript's keyof: Type-Safe Dynamic Properties

Published January 23, 2025
10 min read
Salman Izhar

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.
typescript
interface User {
  id: number;
  name: string;
  email: string;
}

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

Basic Usage Example

typescript
function getProperty<T, K extends keyof T>(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

typescript
interface FormData {
  username: string;
  email: string;
  age: number;
}

type FormErrors = {
  [K in keyof FormData]?: string;
};

class FormValidator {
  private errors: FormErrors = {};

  setError<K extends keyof FormData>(field: K, message: string) {
    this.errors[field] = message;
  }

  getError<K extends keyof FormData>(field: K) {
    return this.errors[field];
  }
}

// Usage
const validator = new FormValidator();
validator.setError("username", "Too short"); // Type-safe!

Real-World Example 2: Event Emitter

typescript
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<K extends keyof Events>(
    event: K,
    callback: (data: Events[K]) => void
  ) {
    if (!this.listeners[event]) {
      this.listeners[event] = [];
    }
    this.listeners[event]!.push(callback);
  }

  emit<K extends keyof Events>(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

typescript
// Make all properties optional
type Partial<T> = {
  [K in keyof T]?: T[K];
};

// Make all readonly
type Readonly<T> = {
  readonly [K in keyof T]: T[K];
};

// Pick specific properties
type Pick<T, K extends keyof T> = {
  [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!

Frontend Strategy

Need a frontend roadmap that supports growth, not churn?

I help product and marketing teams simplify stack decisions, reduce frontend drag, and ship faster without creating long-term maintenance debt.

S

Written by Salman Izhar

Frontend Developer specializing in React, Next.js, and building high-converting web applications.

Learn More