What is the difference between the types A and B?
type A = {[key: string]: string | number | boolean | null}
type B = Record<string, string | number | boolean | null>
What is the difference between the types A and B?
type A = {[key: string]: string | number | boolean | null}
type B = Record<string, string | number | boolean | null>
There is a difference in indexing. When you use Record
, you can use a union of string:
// ok
type B = Record<'a' | 'b', string | number | boolean | null>;
// error
type A = { [key: 'a' | 'b']: string | number | boolean | null };
// works :D
type A_1 = { [key: `a${string}` | `$b${string}`]: string | number | boolean | null };
But you are not able to use unions in aka interface
indexing (see type A).
Please see Symbol and Template String Pattern Index Signatures to better understanding why A_1
works
In general, type A and type B are functionally equivalent and represent object types with arbitrary string keys and values that can be string, number, boolean, or null.
The difference lies in the syntax used to define them, with type A using index signature syntax and type B using the Record utility type.
There is no functional difference. Though generally the Record
type can be quite a bit easier for humans to read.
The Record
utility type is built into TypeScript, but it doesn't require any special syntax or anything to define it. It's simply a shorthand, and you can find its source definition within TypeScript's lib.es5.d.ts
file:
/**
* Construct a type with a set of properties K of type T
*/
type Record<K extends keyof any, T> = {
[P in K]: T;
};
If you were to hover over your type B
in an IDE with TypeScript support, including the TypeScript Playground, you will see that it gets transformed to this:
// type B = Record<string, string | number | boolean | null>
type B = {
[x: string]: string | number | boolean | null;
}
Which is identical to your type definition of A
.