In TypeScript, both Record and Map allow you to store key-value pairs. But they’re not the same, and choosing the right one can improve readability, performance, and type safety in your code.
What is a Record in TypeScript?
A Record is a TypeScript utility type that defines an object with keys of type K and values of type V.
It compiles to a plain JavaScript object.
const links: Record<string, string> = {
home: "/",
about: "/about",
contact: "/contact"
};
console.log(links["about"]); // "/about"
• Keys must be string or number
How to iterate over a record
Option 1: using object.entries
const links = {
home: "/",
about: "/about",
contact: "/contact"
};
type LinkKeys = keyof typeof links;
(Object.entries(links) as [LinkKeys, string][]).forEach(([key, value]) => {
console.log(`${key.toUpperCase()} => ${value}`);
});
Option 2: Using for...in loop
const links = {
home: "/",
about: "/about",
contact: "/contact"
};
// Step 1: Infer the type of the object
type Links = typeof links;
// Step 2: Extract keys as a union type: "home" | "about" | "contact"
type LinkKey = keyof Links;
for (const key in links) {
// Step 3: Guard against prototype pollution
if (Object.prototype.hasOwnProperty.call(links, key)) {
// Step 4: Narrow `key` to LinkKey so it's not just `string`
const typedKey = key as LinkKey;
// Now you have full type safety
const path = links[typedKey];
console.log(`${typedKey} → ${path}`);
}
}
What is a Map?
A Map is an ES6 built-in object that allows you to store key-value pairs with:
•Any key type (not just strings)
•Guaranteed insertion order
•Built-in iteration and utility methods
const linkMap = new Map<string, string>();
linkMap.set("home", "/");
linkMap.set("about", "/about");
linkMap.set("contact", "/contact");
console.log(linkMap.get("about")); // "/about"
How to iterate over a Map
Define links as a Map
const links = new Map([
["home", "/"],
["about", "/about"],
["contact", "/contact"],
]);
*Use typeof + keyof for key constraints to restrict the keys (home, about, contact) *
const linkObj = {
home: "/",
about: "/about",
contact: "/contact"
};
type LinkKeys = keyof typeof linkObj; // "home" | "about" | "contact"
type LinkMap = Map<LinkKeys, string>;
const links = new Map<LinkKeys, string>(Object.entries(linkObj) as [LinkKeys, string][]);
Iteration Method 1: for...of
for (const [key, value] of links) {
// key is strongly typed as "home" | "about" | "contact"
console.log(`${key.toUpperCase()} => ${value}`);
}
Iteration Method 2: .forEach()
links.forEach((value, key) => {
console.log(`${key} => ${value}`);
});
Iteration Method 3: Array.from() with map()
Array.from(links.entries()).map(([key, value]) => {
console.log(`${key}: ${value}`);
});
NOTE: How does Array.from work
const links = new Map([
["home", "/"],
["about", "/about"],
]);
const linkArray = Array.from(links);
// => [ ["home", "/"], ["about", "/about"] ]
linkArray.forEach(([key, value]) => {
console.log(`${key} => ${value}`);
});
Record vs Map — Comparison Table
Feature | Record |
Map |
---|---|---|
Key Types | Only string or number
|
Any type (string , object , etc.) |
Insertion Order | Not guaranteed | Preserved |
Iteration | Use Object.entries()
|
Directly iterable |
Serialization | Easy with JSON.stringify()
|
Requires Object.fromEntries()
|
Utility methods | None |
.get() , .set() , .has() , etc. |
Use Case | Static config/data | Dynamic keys, complex structures |
Example | { home: "/", about: "/about" } |
new Map([["home", "/"], ["about", "/about"]]) |
When Should You Use Which?
💡 Use Case | Choose |
---|---|
Static data, config, known string keys | Record |
Dynamic key-value data, insertion order needed | Map |
You need methods like .has() or .delete()
|
Map |
Easy serialization (e.g., API responses) | Record |
Top comments (0)