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.