Typescript assigning an interface or a type to a Record<string, string>

Viewed 2726

After reading this question or this article, I'm still a bit confused about the subtle differences between an interface and a type.

In this example, my goal is to assign a simple object to a broader Record<string, string> type:

interface MyInterface {
  foobar: string;
}

type MyType = {
  foobar: string;
}

const exampleInterface: MyInterface = { foobar: 'hello world' };
const exampleType: MyType = { foobar: 'hello world' };

let record: Record<string, string> = {};

record = exampleType;      // Compiles
record = exampleInterface; // Index signature is missing

Try it

The assignment is possible when declaring my object with a type, but not when declaring a similar one with an interface. It says that the index signature is missing, but to my (limited) understanding of index signatures, none of MyType and MyInterface actually have one.

What is the reason why the last line does not compile whereas the previous one does?

1 Answers

Record<string, string> is the same as { [key: string]: string }. A subset is allowed to be assigned to this index signature type is only possible if all properties of that type are known and can be checked against this index signature. In your case, everything from exampleType is assignable to Record<string, string>. This can be only checked for object literal types, as object literal types can't be changed once you declared them. Thus, the index signature is known.

Source: https://github.com/microsoft/TypeScript/pull/7029

In contrast, interfaces are not final the moment you declare them. There is always the possibility of adding new members to the same interface due to declaration merging.

Related