When you need to store collections of key–value pairs in TypeScript, two popular options are Record
and Map
. They serve similar purposes—both map keys to values—but differ in syntax, capabilities, and use-cases. Understanding these differences helps you pick the right tool for the job.
1. Using Plain Objects with Index Signatures
Traditionally, JavaScript objects are used as dictionaries:
interface User {
id: string;
name: string;
}
type Users = { [key: string]: User };
const users: Users = {
abc123: { id: 'abc123', name: 'John Doe' },
xyz789: { id: 'xyz789', name: 'Jane Doe' },
};
console.log(users['abc123']); // { id: 'abc123', name: 'John Doe' }
The { [key: string]: User }
syntax is called an index signature. It tells TypeScript that users
can have any number of string keys, each mapping to a User
.
2. Record<K, T>
– A Cleaner Type Alias
Record
is a built-in TypeScript utility type that makes the above pattern more concise:
interface User {
id: string;
name: string;
}
type Users = Record<string, User>;
const users: Users = {
abc123: { id: 'abc123', name: 'John Doe' },
xyz789: { id: 'xyz789', name: 'Jane Doe' },
};
Benefits of Record
:
- Shorter, easier to read than an index signature.
- Lets you constrain keys if you want a fixed set:
type Roles = Record<'admin' | 'editor', User>;
- Perfect for plain JSON-like objects where keys are strings (or numbers/symbols) known at compile time.
Limitations:
- Keys are always strings (or a union of string literals).
- Methods such as
.size
or ordered iteration aren’t built in—you treat it like a normal object.
3. Map<K, V>
– A Full-Featured Key–Value Store
ECMAScript Map
is a class that offers more flexibility than a plain object:
interface User {
id: string;
name: string;
}
const usersMap = new Map<string, User>();
usersMap.set('abc123', { id: 'abc123', name: 'John Doe' });
usersMap.set('xyz789', { id: 'xyz789', name: 'Jane Doe' });
console.log(usersMap.get('abc123')); // { id: 'abc123', name: 'John Doe' }
Advantages of Map
:
- Keys can be any value, not just strings (objects, numbers, functions, etc.).
- Maintains insertion order, which can be important for iteration.
- Provides convenient methods:
.get
,.set
,.has
,.delete
,.size
, and built-in iterators.
Trade-offs:
- Slightly more overhead than a plain object.
- Not as easy to serialize to JSON directly (
JSON.stringify
won’t automatically include map entries).
4. When to Use Which
Scenario | Prefer |
---|---|
Static or JSON-like data, simple string keys | Record |
Need arbitrary key types (objects, numbers, etc.) | Map |
Require ordered iteration or frequent insert/delete | Map |
Want lightweight, serializable structure | Record |
Quick Recap
-
Record<K, V>
: TypeScript utility for object literals where keys are strings or a union of string literals. Clean and lightweight. -
Map<K, V>
: ECMAScript class with rich methods, supports any key type and preserves insertion order.
Choosing between them comes down to your requirements:
- For configuration data, caching simple IDs, or working with JSON:
Record
(or an index signature) is perfect. - For dynamic, runtime-driven collections with complex keys or heavy mutation:
Map
is the better fit.
By understanding these tools, you can model key–value data in TypeScript with the right balance of simplicity and power.
Top comments (0)