Convert Dynamic-Key JSON Objects to TypeScript Index Signatures

Learn how to convert JSON objects with dynamic or unknown keys into TypeScript types using index signatures and the Record utility type.

Advanced Patterns

Detailed Explanation

Dynamic Keys in JSON

Some JSON objects use dynamic keys — keys that are not known ahead of time but follow a pattern. Common examples include dictionaries, lookup tables, and locale maps.

Example JSON

{
  "translations": {
    "en": "Hello",
    "ja": "こんにちは",
    "es": "Hola",
    "fr": "Bonjour"
  },
  "userScores": {
    "user_001": 95,
    "user_002": 82,
    "user_003": 71
  }
}

Generated TypeScript

interface Root {
  translations: { [key: string]: string };
  userScores: { [key: string]: number };
}

Index Signature Syntax

An index signature tells TypeScript that an object can have any number of properties as long as the keys and values match the specified types:

{ [key: string]: ValueType }

Using Record<K, V>

The Record utility type is equivalent and often preferred for readability:

interface Root {
  translations: Record<string, string>;
  userScores: Record<string, number>;
}

Narrowing the Key Type

If you know the possible keys, narrow them with a union:

type Locale = "en" | "ja" | "es" | "fr";

interface Root {
  translations: Record<Locale, string>;
}

This gives you compile-time errors when accessing a key not in the union and enables exhaustive checking.

Mixed Structures

Sometimes an object has known properties and dynamic ones:

interface Config {
  version: string;
  [key: string]: string | number;
}

Be careful: the index signature must be a supertype of all named properties. Here, version: string is compatible with string | number, so it works.

When to Use

Use index signatures for lookup tables, dictionaries, i18n maps, and any structure where the set of keys is data-driven rather than schema-driven.

Use Case

You receive a translations object from a CMS where locale codes are keys and translated strings are values, and you need a type that permits any locale code while enforcing string values.

Try It — JSON to TypeScript

Open full tool