Understanding TypeScript Object.entries Type Safety with Generic Types

Understanding TypeScript Object.entries Type Safety with Generic Types

The Problem

When using Object.entries() in TypeScript, we lose the relationship between keys and their value types.

For example:

type User = {
  age: number;
  name: string;
  active: boolean;
}

// TypeScript gives us [string, any][]
// We want [('age' | 'name' | 'active'), (number | string | boolean)][]
const entries = Object.entries(user)

But even worse, we lose the specific relationships. We can't be sure that when we have the 'age' key, we get a number.

The Solution

We can create a type that preserves these relationships:

type Entries<T> = Array
  {
    [K in keyof T]: [K, T[K]]
  }[keyof T]
>

Let's break down how this works:

  1. [K in keyof T] - Maps over each key in T

  2. [K, T[K]] - Creates a tuple of the key and its value type

  3. [keyof T] - Indexes into the mapped type to create a union

  4. Array<...> - Makes it an array of these tuples

Using It

type User = {
  age: number;
  name: string;
  active: boolean;
}

// Now TypeScript knows:
// If key is 'age', value is number
// If key is 'name', value is string
// If key is 'active', value is boolean
const entries = Object.entries(user) as Entries<User>

for (const [key, value] of entries) {
  if (key === 'age') {
    // TypeScript knows value is number
    console.log(value + 1)
  }
  if (key === 'name') {
    // TypeScript knows value is string
    console.log(value.toUpperCase())
  }
}

Why This Matters

This pattern is particularly useful when:

  • Building type-safe APIs

  • Working with configuration objects

  • Processing data with specific key-value relationships

  • Creating generic utility functions

The Power of Mapped Types

This solution showcases several advanced TypeScript features:

  1. Mapped types for transforming each property

  2. Tuple types for key-value pairs

  3. Indexed access types to get value types

  4. Array types with unions

By combining these features, we maintain type safety while working with object entries.