Learn how to type dynamic object dictionaries using index signatures and map over existing type keys to build new types.
Discover how TypeScript infers types automatically and how let versus const declarations shape wide types versus narrow literal types.
In JavaScript, objects often act as lookup dictionaries with unknown dynamic property keys (for example, caching objects or user dictionaries).
An Index Signature defines the data type of dynamic keys and values for objects whose exact property names are not known ahead of time:
// Index signature: key must be string, value must be number
interface UserScores {
[username: string]: number;
}
const leaderboard: UserScores = {
alex: 100,
sarah: 250,
maria: 180,
};
leaderboard.david = 300; // Valid dynamic key addition!
A Mapped Type builds a new object shape by iterating over keys of an existing type using in keyof syntax:
type Permissions = "canRead" | "canWrite" | "canDelete";
// Mapped Type: Maps every permission string to a boolean!
type UserPermissionFlags = {
[K in Permissions]: boolean;
};
/*
Equivalent to:
type UserPermissionFlags = {
canRead: boolean;
canWrite: boolean;
canDelete: boolean;
};
*/
const myFlags: UserPermissionFlags = {
canRead: true,
canWrite: false,
canDelete: false,
};
You can add or remove readonly or optional ? modifiers inside mapped types using + or -:
// Make all properties optional
type Optional<T> = {
[K in keyof T]?: T[K];
};
leaderboard["unknownUser"]) returns number by default, even though it evaluates to undefined at runtime! Enable noUncheckedIndexedAccess: true in tsconfig.json to force number | undefined safety!Use mapped types for reusable type transformations. Next, let's enter Phase 3 and master Generics!