为什么不能将接口分配给 Record<string, unknown>?

Why can't an interface be assigned to Record<string, unknown>?

提问人:Stephan Kulla 提问时间:1/20/2021 最后编辑:Jerryh001Stephan Kulla 更新时间:11/17/2023 访问量:27456

问:

我刚刚注意到无法将接口分配给(游乐场链接):Record<string, unknown>

interface Foo {
    foo: number
}

const foo: Foo = { foo: 1 }
const bar: Record<string, unknown> = foo
//    |-> Error: Type 'Foo' is not assignable to type 'Record<string, unknown>'
//               Index signature is missing in type 'Foo'.(2322)

但是,当省略类型声明时,同样的情况是可能的(playground 链接):Foo

const foo = { foo: 1 }
const bar: Record<string, unknown> = foo // no error here

问题:为什么两个例子之间有区别?对我来说,变量的简化类型在两个示例中是相同的......接口不应该分配给吗?fooFooRecord<string, unknown>

在我的理解中,它等价于,因此任何接口都应该分配给它。此外,@typescript-eslint/ban-types 建议使用 代替 .Record<string, unknown>objectRecord<string, unknown>object

言论:第一个示例在使用 (playground link) 或 (playground link 而不是 时起作用。objectRecord<string, any>Record<string, unknown>

TypeScript 对象 compiler-errors 类型转换

评论


答:

4赞 D M 1/20/2021 #1

编辑:@Lesiak上面有正确答案。我把它留给相关答案的链接。

诚然,我在这里有点不知所措,但我正在浏览这个答案,我看到:

TypeScript 的安全性很大程度上来自于这样一个事实,即 [...] 它只允许你将一个对象视为字典,如果它知道它明确地打算作为一个字典。

这与我的测试一致。修改接口以显式视为索引不会产生错误。(游乐场链接Foo.foo)

interface Foo {
    [foo: string]: number
}

const foo = { foo: 1 }
const bar: Record<string, unknown> = foo

这并不能完全回答您的问题,就像您的显式界面一样,但也许知识渊博的人可以从这里获取它。Record<string, any>

评论

2赞 Stephan Kulla 1/20/2021
实际上应该是正确的解决方案 playground 链接,因为它的意思是:“具有类型属性的对象,它可以用作字典”interface Foo { foo: number, [key: string]: unknown }foonumber
1赞 Stephan Kulla 1/20/2021
在链接的线程中,有一个问题为什么从 5 天前开始:github.com/microsoft/TypeScript/issues/... :-)我也想知道为什么这样会起作用......Record<string, any>
39赞 Lesiak 1/20/2021 #2

您遇到 Index signature is missing in type (only on interfaces, not on type alias) #15300

当您将接口更改为类型时,该代码将起作用:

type Foo = {
    foo: number
}

const foo: Foo = { foo: 1 };
const bar: Record<string, unknown> = foo;