Data report"State of code review 2024" is now liveRead the full report

The Typescript Record utility type

Kenny DuMez
Kenny DuMez
Graphite software engineer

TypeScript provides various ways to define and manipulate object types and collections. One versatile utility type is Record, which facilitates the creation of an object type with a set of known properties. This guide explores the Record type in TypeScript, discussing its syntax, usage scenarios, differences with other data structures like Map, and techniques for iteration and recursion.

A Record in TypeScript is a generic utility type that constructs an object type with a specific set of keys of a given type, and where all the values are of another specified type. The Record type is defined as Record<K, T>, where K represents the type of the keys and T represents the type of the values.

Here's a basic example of a Record:

Terminal
type UserRecord = Record<string, number>
const ages: UserRecord = {
Alice: 25,
Bob: 30
}

In this example, UserRecord is a Record type where each key is a string and each value is a number.

Record is especially useful when you need to ensure all properties of an object have the same type, or when you want to map a fixed set of keys to values where the keys are known in advance but are too numerous or inconvenient to list individually in a type definition.

Both Record and Map store key-value pairs, but there are important differences:

  • Type strictness: Record is more type-strict, enforcing all keys to be of one type and all values to be of another type. Map, however, can have mixed type keys and values if specified.
  • Iteration: Map has built-in methods for iteration, like .keys(), .values(), and .entries(), making it more suitable for cases where order of elements matters or when elements are frequently added and removed.
  • Serialization: Record objects are just regular JavaScript objects and can be serialized directly using JSON.stringify(). Map requires conversion to an array or another structure for serialization.
Terminal
const record: Record<string, number> = { Alice: 25, Bob: 30 }
const map = new Map<string, number>([
['Alice', 25],
['Bob', 30]
])
console.log(JSON.stringify(record)) // {"Alice":25,"Bob":30}
console.log(JSON.stringify(Array.from(map.entries()))) // [["Alice",25],["Bob",30]]

To iterate over a Record, you can use Object class methods such as Object.keys(), Object.values(), and Object.entries(). Here's how you can loop over a Record:

Terminal
const userAges: Record<string, number> = { Alice: 25, Bob: 30 }
// Using Object.keys() to get all keys
for (const userName of Object.keys(userAges)) {
console.log(userName)
}
// Using Object.values() to get all values
for (const age of Object.values(userAges)) {
console.log(age)
}
// Using Object.entries() to get key-value pairs
for (const [userName, age] of Object.entries(userAges)) {
console.log(`${userName} is ${age} years old`)
}

Recursive Record types are useful for defining objects with nested structures of the same type. Here’s how you can define a recursive Record:

Terminal
type RecursiveRecord = Record<string, number | RecursiveRecord>
const nestedRecord: RecursiveRecord = {
level1: {
level2: {
value: 10
},
anotherValue: 5
}
}
function printRecord(record: RecursiveRecord) {
for (const key in record) {
if (typeof record[key] === 'object') {
printRecord(record[key] as RecursiveRecord)
} else {
console.log(`${key}: ${record[key]}`)
}
}
}
printRecord(nestedRecord)
  1. Use Record for fixed schema objects: When the keys are known and uniform types are required, Record is an excellent choice.
  2. Consider using Map for dynamic collections: If the collection grows dynamically and keys are not predetermined, a Map might be more appropriate.
  3. Leverage TypeScript’s type safety: Always specify the types for keys and values to fully leverage TypeScript's type-checking.

For further reading on records in TypeScript, see the official documentation.

Stay unblocked. Ship faster.
Experience the new developer workflow - create, review, and merge code continuously. Get started with one command.
Learn more

Give your PR workflow
an upgrade today

Stack easier | Ship smaller | Review quicker

Or install our CLI.
Product Screenshot 1
Product Screenshot 2