What Is the TypeScript Record Type?

Learn how the TypeScript Record utility type works

Introduced in TypeScript 2.1, Record<K, T> is a utility type. It denotes an object type that has keys/properties of type K and values of type T. To illustrate this, let's consider the following example:

type Keys = 'a' | 'b';
type Values = 'foo' | 'bar';

const obj: Record<Keys, Values> = {
    a: 'foo',
    b: 'bar',
}

This is equivalent to:

type Keys = 'a' | 'b';
type Values = 'foo' | 'bar';

const obj: { [K in Keys]: Values } = {
    a: 'foo',
    b: 'bar',
}

You could, of course, use either one. Record<Keys, Values> is merely a convenience mapping utility type. Under the hood, for those of you who're curious, Record<Keys, Values> is defined the same way:

// TypeScript 2.9+
type Record<K extends keyof any, T> = {
    [P in K]: T;
}
// TypeScript 2.1+
type Record<K extends string, T> = {
    [P in K]: T;
}

Please note that in TypeScript 2.1 Record mapped types only had support for string keys, and any non-string values passed in as the key got coerced into a string. In TypeScript 2.9, however, support for number and symbol keys was added.

Indexable Type Vs. Record Type

In certain cases, the Record type can be compared to indexable types, for example:

type Values = 'foo' | 'bar';

const obj: Record<string, Values> = {
    a: 'foo',
    b: 'bar',
}

// is equivalent to:
const obj: { [key: string]: Values } = {
    a: 'foo',
    b: 'bar',
}

However, they have some notable differences:

Record<K, T> Type Indexable Type
K in Record<K, T> must be a string, number or a symbol, and can be a union type. The index signature parameter type must be either a string or a number, and cannot be a union type.

The following show examples of when you cannot use indexable types:

type Keys = 'a' | 'b';
type Values = 'foo' | 'bar';

const obj: { [k: Keys]: Values } = {
    a: 'foo',
    b: 'bar',
}

// error: An index signature parameter type cannot be a union type. Consider using a mapped object type instead.
interface Types {
    a: string;
    b: string;
}

const obj: { [k: Types]: Values } = {
    a: 'foo',
    b: 'bar',
}

// error: An index signature parameter type must be either 'string' or 'number'.

The following shows an example of when you cannot use Record type:

interface Types {
    a: string;
    b: string;
}

const obj: Record<Types, Values> = {
    a: 'foo',
    b: 'bar',
}

// error: Type 'Types' does not satisfy the constraint 'string | number | symbol'.

Hope you found this post useful. It was published . Please show your love and support by sharing this post.