我对 TS 的理解还不足以真正解决这个问题,但我会根据我设法查找的内容提供一些观察结果。
首先:object
是任何非原始的。所以,例如。函数是object
s 和字符串不是:
let bar1: object = alert // typechecks
let bar2: object = 'a' // doesn't
的特殊属性{}
另一方面,“可以从任何非空/未定义值分配”:https://gist.github.com/OliverJAsh/381cd397008309c4a95d8f9bd31adcd7?permalink_comment_id=2890808#gistcomment-2890808 https://gist.github.com/OliverJAsh/381cd397008309c4a95d8f9bd31adcd7?permalink_comment_id=2890808#gistcomment-2890808
{} 是空类型,可以从任何非 null/非未定义类型分配。请记住此处的结构类型:减少类型中的属性数量(不应该)永远不会减少可分配给该类型的类型数量(注意,过多的属性检查不是可分配性的因素;它是单独的检查)。
请注意这里一些有问题的对称性:字符串应该可分配给 { length: number },并且对于任何类型 { r0; r1; r2...},该类型的可分配值也应可分配给 { r1; r2...}。因此,如果 string 可分配给 { length: number } (这绝对应该是),那么 string 也必须可分配给 { },即使它不是一个对象。
所以这是之间的区别{}
and object
,如图所示:
let bar0: {} = 'a' // typechecks
let bar1: object = 'a' // doesn't
这意味着一个明显可疑的部分是{} extends object
:
let bar0: {} = 'a'
let bar1: object = {}
bar1 = bar0 // shouldn't work but it does
https://github.com/microsoft/TypeScript/pull/49119 https://github.com/microsoft/TypeScript/pull/49119是关于另一个方向——事物的可分配性{}
。我搜索过但没有找到任何有关分配的信息{}
对事物。
我不确定 TS 是否真的关心维护原语(例如string
) 不能以object
。如果它确实关心,那么正如您提到的,应该有一个false
在前两对中的每一对中。
但是没问题。假设它不在乎。
第二个不确定的部分是以下之间的差异:
{} extends Record<string, unknown> = true
object extends Record<string, unknown> = false
TypeScript 索引签名的实际含义是什么? https://stackoverflow.com/questions/58458308/what-does-a-typescript-index-signature-actually-mean可能会提供有关/为什么第二个是的线索false
.
我花了最后一个小时试图理解索引签名(由Record
)并且我无法为它们想出一个有意义的清晰语义。
也许唯一好的解释是“如果很明显您将要注入错误键入的键/值,TS 想要抱怨,但否则它不会抗议太多”。所以object
是一种垃圾堆,不应该最终进入{[key: string]: unknown}
, but {}
很好,尽管它可能绝对也是垃圾堆。
我希望 TS 类型检查规则实际上写在某个地方。