1. Introduction
Sometimes you don't know all the property names an object will have ahead of time — for example, a dictionary mapping arbitrary usernames to user records. An index signature lets an interface or type describe this pattern: 'any property whose key is of this type maps to a value of this type,' enabling dynamic property access while still being type-checked.
Cricket analogy: Like a scorer's ledger where you don't know every player's name in advance but know each name maps to an innings record, so the sheet is designed as any player name mapping to a score entry.
2. Syntax
interface StringDictionary {
[key: string]: string;
}
const colors: StringDictionary = {
primary: "blue",
secondary: "green",
};
colors.accent = "orange"; // dynamic key, still type-checked as string
console.log(colors["primary"], colors.accent);3. Explanation
An index signature has the form [key: KeyType]: ValueType, where KeyType must be string, number, symbol, or a union/template-literal of those. It tells TypeScript that any property accessed on the object with a key of that type will resolve to ValueType. This is essential for describing dictionary-like or map-like objects whose exact key set isn't known statically.
Cricket analogy: The form [playerName: string]: BattingStats tells the scoreboard system that any string key resolves to a BattingStats object, essential for describing a squad list whose exact roster isn't fixed before the tournament starts.
A critical rule is that every explicitly named property on the same interface must be compatible with the index signature's value type. If [key: string]: number is declared, you cannot also declare name: string in the same interface, because name is a string-keyed property (all string keys are covered by the index signature) whose value type (string) is incompatible with the index signature's declared value type (number). Named properties are essentially special cases of the index signature and must be assignable to it.
Cricket analogy: If a scoreboard declares [key: string]: number for every stat, you can't also add a captain: string field, because captain is itself a string-keyed entry that must produce a number like every other stat the sheet promises.
Gotcha: a numeric index signature ([key: number]: T) does not restrict object keys to only numbers at runtime — JavaScript object keys are always strings (or symbols) under the hood. TypeScript allows a numeric index signature mainly to model array-like or tuple-like structures, and requires that the numeric index signature's value type be a subtype of any string index signature's value type if both are present, since numeric keys are ultimately also string keys.
4. Example
interface Scores {
[studentName: string]: number;
}
const scores: Scores = {
Alice: 92,
Bob: 85,
};
scores.Carol = 78; // valid: value matches index signature's number type
function average(record: Scores): number {
const values = Object.values(record);
const total = values.reduce((sum, v) => sum + v, 0);
return total / values.length;
}
console.log(average(scores));
// Named property must be compatible with the index signature's value type.
interface MixedRecord {
[key: string]: number;
total: number; // OK, matches 'number'
// label: string; // Error if uncommented: 'string' is not assignable to 'number'
}
const mixed: MixedRecord = { total: 0, extra: 15 };
console.log(mixed.total, mixed.extra);5. Output
85
0 156. Key Takeaways
- An index signature
[key: string]: Tdescribes objects with dynamic, not-fully-known property keys, all mapping to type T. - Valid index signature key types are string, number, symbol, or unions/template literals of those.
- Every explicitly named property must have a value type compatible with the index signature's value type.
- JavaScript keys are always strings/symbols at runtime; a numeric index signature is a modeling convenience for array-like shapes.
- Index signatures are ideal for dictionaries, lookup tables, and dynamic configuration objects.
Practice what you learned
1. What does the index signature `[key: string]: number` mean for an interface?
2. If an interface has `[key: string]: number`, why can't it also declare `label: string` as a named property?
3. At runtime, are JavaScript object property keys ever actually numbers?
4. Which of the following is a valid key type for a TypeScript index signature?
5. What kind of TypeScript objects are index signatures most commonly used to model?
Was this page helpful?
You May Also Like
Interfaces in TypeScript
Learn how TypeScript interfaces describe the shape of objects using structural typing, and why they are the primary tool for contract-based design.
interface vs type in TypeScript
Compare TypeScript's `interface` and `type` keywords — when each is preferable, and what each can and cannot express.
Mapped Types in TypeScript
Transform every property of an existing type into a new type using `{ [K in keyof T]: ... }`, with modifiers and key remapping.
Utility Types in TypeScript
Learn TypeScript's built-in generic utility types — Partial, Required, Readonly, Pick, Omit, and Record — for transforming existing types.
Arrays in TypeScript
How to type homogeneous lists of values using the T[] and Array<T> syntaxes, including multi-dimensional and readonly arrays.
Related Reading
Related Study Notes in Programming
Browse all study notesApache Spark Study Notes
Programming · 30 topics
ProgrammingApache Flink Study Notes
Programming · 30 topics
ProgrammingHadoop Study Notes
Programming · 30 topics
ProgrammingSnowflake Study Notes
Programming · 30 topics
ProgrammingApache Airflow Study Notes
Programming · 30 topics
Programmingdbt (Data Build Tool) Study Notes
Programming · 30 topics