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

问题描述 投票:0回答:3

我刚刚注意到接口无法分配给

Record<string, unknown>
playground链接):

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)

但是,当省略

Foo
的类型声明时,同样是可能的(playground 链接):

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

问题: 为什么两个示例之间存在差异?对我来说,变量

foo
的简化类型在两个示例中都是相同的......接口
Foo
不应该分配给
Record<string, unknown>
吗?

根据我的理解,

Record<string, unknown>
相当于
object
,因此任何接口都应该可以分配给它。另外 @typescript-eslint/ban-types 建议使用
Record<string, unknown>
而不是
object

备注: 第一个示例在使用

object
(playground link) 或
Record<string, any>
(playground link) 代替
Record<string, unknown>
时有效。

typescript object types compiler-errors type-conversion
3个回答
43
投票

您遇到过类型中缺少索引签名(仅在接口上,不在类型别名上)#15300

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

type Foo = {
    foo: number
}

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

6
投票

编辑:@Lesiak 上面有正确的答案。我留下这个只是为了相关答案的链接。

诚然,我有点超出了我的深度,但我正在浏览这个答案,我看到:

[A]TypeScript 安全性的很大一部分来自于这样一个事实:[...]只有当它知道它明确地打算作为一个对象时,它才会让您将对象视为字典。

这与我的测试一致。修改您的界面以明确将

Foo.foo
视为索引不会产生错误。 (游乐场链接)

interface Foo {
    [foo: string]: number
}

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

这并不能完全回答您的问题,因为

Record<string, any>
适用于您的显式界面,但也许知识渊博的人可以从这里获取它。


0
投票

Record<string, unknown>
需要索引签名(参见 GitHub 上的此评论)。

所以这无法编译:

interface X {
  a: boolean;
  b: number;
}

const x: X = { a: true, b: 1 };
const y: Record<string, unknown> = x;  // error

编译成功:

interface X {
  [key: string]: unknown;
  a: boolean;
  b: number;
}

const x: X = { a: true, b: 1 };
const y: Record<string, unknown> = x;  // okay

这也可以成功编译,因为推断了类型的索引签名(参见 GitHub 上的此评论):

type X {
  a: boolean;
  b: number;
}

const x: X = { a: true, b: 1 };
const y: Record<string, unknown> = x;  // okay

这也可以成功编译,因为

Record<string, any>
不需要索引签名(参见 GitHub 上的此评论):

interface X {
  a: boolean;
  b: number;
}

const x: X = { a: true, b: 1 };
const y: Record<string, any> = x;  // okay
© www.soinside.com 2019 - 2024. All rights reserved.