Index signatures
TypeScript · Reference cheat sheet
Index signatures
TypeScript · Reference cheat sheet
📋 Overview
Index signatures type objects used as maps: \{ [key: string]: V \}. Prefer Record<K, V>, Map, or explicit keys when the key set is known. Combine carefully with declared properties — values must be assignable to the index type.
🔧 Core concepts
- String / symbol / number / template —
[k: string]: T,[k: number]: T,[k: `id-$\{string\}`]: T. - Compatibility — every explicit property must match the index value type.
Record<K, V>— mapped type sugar for key unions.- Readonly index —
[k: string]: readonly T[]/Readonly<Record<…>>. noUncheckedIndexedAccess— indexed reads include| undefined.
💡 Examples
interface Dict {
[key: string]: number;
length: number; // OK — number assignable to number
// name: string; // error — string not assignable to number
}
const scores: Record<string, number> = { alice: 10, bob: 8 };
scores.carol = 12;
type IdMap = { [id: `user-${string}`]: { name: string } };
const users: IdMap = {
"user-1": { name: "Ada" },
};
// Number index (arrays / array-like)
interface StringArray {
[index: number]: string;
}
// Prefer known keys when possible
type Role = "admin" | "user";
const permissions: Record<Role, string[]> = {
admin: ["read", "write", "billing"],
user: ["read"],
};
function get(map: Record<string, number>, key: string) {
return map[key]; // number | undefined if noUncheckedIndexedAccess
}⚠️ Pitfalls
- String index signatures weaken
keyofto includestring. - Mixing required props with a broad index often forces props to
string | …. - Prefer
Map<K, V>for frequent add/delete and non-string keys. - Empty object
\{\}is not a safe “any key” type — useRecordor index sig. - Numeric keys are coerced to strings at runtime — type them intentionally.