Differences between Record<string, any> and {}?

Viewed 8744

The only difference I see is that you can't add additional properties to {} but you can to Record<string, any>. Is there anything else that I'm missing?

Example code (playground link):

const one: Record<string, any> = { foo: 1 }
one.bar = 2

const two: {} = { foo: 1 }
two.bar = 2 // Property 'bar' does not exist on type '{}'.(2339)
2 Answers

Ok so the real question is why we can assign any object into {}. This is more about language design choices. Language is build over structural subtyping compatibility.

Type compatibility in TypeScript is based on structural subtyping. Structural typing is a way of relating types based solely on their members. This is in contrast with nominal typing.

It means we can assign to the more loose type values of its subtypes. In your code {} is widest type of object, we can say its parent type for every object type, in other words every other object type is a subtype of {}. Below is some example checks:

type ISubTypeOfEmptyObj<T> = T extends {} ? true : false
type Check1 = ISubTypeOfEmptyObj<{bar: 2}> // yes it is
type Check2 = ISubTypeOfEmptyObj<{foo: 2, bar: 'a'}> // yes it is
type Check3 = ISubTypeOfEmptyObj<number> // surprisingly that is also true
const a: {} = 1; // no error 

What does it proof - fact that you can make instance of {} from a thin air almost (only null and undefined values cannot be members of {}). But also it holds true that after initialization you cannot just set some properties to such value, as the type says there are none. In other words you can make {} from almost anything, but you can use it after only like empty object.

Record<string, any> is more strict type than {}, for example every array type will be assignable to {}, and not assignable to Record<string, any>, the same holds for other types like string or number. Record<string, any> represents all object with any string properties, therefor you can append any string property to the object, as type will hold.

The type {} only matches an empty object.

Record<string, any> would be similar to { [key: string]: any}

UPDATE: My first sentence was false. The type {} matches pretty much anything like said in the accepted answer

Related