2

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>
Sebastian Barth
  • 4,079
  • 7
  • 40
  • 59
  • 1
    On the face of it, there is no difference, yet I had a situation this week where the `Record` variant triggered a "nesting is excessively deep" error and the indexed type did not. – Robby Cornelissen May 10 '23 at 09:58
  • 1
    @RobbyCornelissen you can check my [answer](https://stackoverflow.com/questions/37233735/interfaces-vs-types-in-typescript#answer-64971386), the second part. THis is because interfaces are eagerly evaluated whereas types not. This syntax `[key: string]` is aka `interface` indexing – captain-yossarian from Ukraine May 10 '23 at 11:07
  • Could you [edit] the title to say `Record` vs `{[key: string]: B}`? Or maybe edit the question to indicate that `string` is just an example and you want to understand the difference in general? It has an effect on the answer. – jcalz May 10 '23 at 13:57

3 Answers3

2

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

1

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.

Luboš Hájek
  • 342
  • 4
  • 14
1

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;
}

TypeScript Playground

Which is identical to your type definition of A.

Mark Hanna
  • 3,206
  • 1
  • 17
  • 25