Typescript为Record〈string,string>分配接口或类型

14ifxucb  于 2023-04-07  发布在  TypeScript
关注(0)|答案(2)|浏览(435)

在阅读this question或本文之后,我仍然对interfacetype之间的细微差别感到有点困惑。
在这个例子中,我的目标是将一个简单的对象分配给一个更广泛的Record<string, string>类型:

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

试试看
当用type声明我的对象时,赋值是可能的,但当用interface声明类似的对象时,赋值就不可能了。它说索引签名丢失了,但根据我对索引签名的(有限的)理解,MyTypeMyInterface实际上都没有索引签名。
为什么最后一行不能编译,而前一行可以编译?

vsmadaxz

vsmadaxz1#

Record<string, string>{ [key: string]: string }相同。允许将子集分配给此 * 索引签名类型 * 只有在该类型的所有属性都已知并且可以针对此索引签名进行检查时才可能。在您的情况下,来自exampleType的所有内容都可以分配给Record<string, string>。这只能检查对象文字类型,as对象文字类型一旦声明就不能改变。因此,索引签名是已知的。
来源:https://github.com/microsoft/TypeScript/pull/7029
相反,接口在你声明的那一刻并不是最终的。由于声明合并,总是有可能向同一个接口添加新成员。

o3imoua4

o3imoua42#

有一种解决方法,即提供一个与您要分配的接口兼容的中间类型:

interface MyInterface {
  foobar: string;
}

type MyType = {
  foobar: string;
};

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

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

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

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

相关问题