TypeScript Index Signatures

🔑 TypeScript Index Signatures (Beginner → Advanced)

Index Signatures in TypeScript let you describe the shape of objects with dynamic (unknown) property names.
They are essential when working with maps, dictionaries, API responses, configs, and dynamic keys.


1️⃣ What Is an Index Signature?

An index signature defines the type of values for properties when the property names are not known in advance.

type StringMap = {
[key: string]: string;
};

✔ Any string key
✔ Value must be a string


2️⃣ Basic Index Signature Example ⭐

type ErrorMessages = {
[field: string]: string;
};
const errors: ErrorMessages = {
email: “Invalid email”,
password: “Too short”
};

✔ Common for form validation errors


3️⃣ Index Signature with number Keys ⭐

type NumberMap = {
[index: number]: string;
};
const arrLike: NumberMap = {
0: “zero”,
1: “one”
};

📌 In JavaScript, number keys are converted to strings, but TS treats them separately for typing.


4️⃣ Mixing Known Properties with Index Signatures ⚠️

When you add explicit properties, their types must be compatible with the index signature.

type UserMap = {
[key: string]: string;
name: string; // ✅ OK
// age: number; // ❌ Error (must be string)
};

✔ All properties must match the index signature value type


5️⃣ Readonly Index Signatures 🔒

type ReadonlyConfig = {
readonly [key: string]: number;
};
const cfg: ReadonlyConfig = {
retries: 3
};

// cfg.retries = 5; ❌ Error

✔ Prevents mutation


6️⃣ Optional vs Index Signature ❓

type User = {
name: string;
email?: string;
};

👆 This is not an index signature.

Index signature allows any key:

type UserExtras = {
[key: string]: string | undefined;
};

7️⃣ Index Signatures vs Record ⭐⭐

Index Signature

type Permissions = {
[role: string]: string[];
};

Record (Preferred Often)

type Role = "admin" | "user";

type Permissions = Record<Role, string[]>;

Record is safer when keys are known
✔ Index signatures when keys are truly dynamic


8️⃣ Index Signatures with Union Value Types ⭐

type Config = {
[key: string]: string | number | boolean;
};
const settings: Config = {
theme: “dark”,
retries: 3,
debug: true
};

✔ Very common in configuration objects


9️⃣ Index Signatures + Mapped Types 🔥

type Flags<T extends string> = {
[K in T]: boolean;
};
type FeatureFlags = Flags<“darkMode” | “beta”>;

const flags: FeatureFlags = {
darkMode: true,
beta: false
};

✔ Strongly typed keys
✔ Safer than raw index signatures


🔟 Index Signatures with unknown (Safer) ⭐

type SafeMap = {
[key: string]: unknown;
};
function read(map: SafeMap, key: string) {
const value = map[key];
if (typeof value === “string”) {
console.log(value.toUpperCase());
}
}

✔ Forces type narrowing
✔ Better than any


1️⃣1️⃣ Common Mistakes ❌

  • Using index signatures when keys are known

  • Forgetting that all properties must match the value type

  • Using any instead of unknown

  • Overusing index signatures instead of Record

  • Expecting number index signatures to differ at runtime


📌 Interview Questions (Must Prepare)

  1. What is an index signature?

  2. Difference between index signature and Record?

  3. Can we mix fixed properties with index signatures?

  4. Why must property types match the index signature?

  5. string vs number index signatures?

  6. When should index signatures be avoided?


🔥 Real-World Use Cases

  • API response objects with dynamic keys

  • Localization dictionaries

  • Feature flags

  • Form validation errors

  • Caching & lookup tables


✅ Summary

✔ Index signatures handle dynamic object keys
✔ Syntax: [key: string]: ValueType
✔ All properties must match the value type
✔ Prefer Record when keys are known
✔ Use unknown for safety
✔ Essential for real-world TypeScript & interviews

You may also like...