【发布时间】:2021-07-23 06:24:00
【问题描述】:
考虑以下代码:
const testOne: Record<"foo"|"bar", string> = {
"foo": "xyz"
};
const testTwo: Record<string, string> = {
"foo": "xyz"
};
第一个示例导致缺少属性“bar”的错误。第二个示例不会导致错误。这让我感到困惑,因为我试图了解 Record 是否是一种暗示其键类型的所有可能值的现有属性的类型。
如果 Record 是一种不要求所有可能的键实际存在于该类型的值中的类型,那么第一个示例不应导致错误。
如果 Record is 是一种要求所有可能的键实际存在于该类型的值中的类型,那么第二个示例也应该导致错误。在这种情况下,不可能构造该类型的值,因为可能的键集是无限的。
如果有第三种选择——这似乎是根据我尝试编译示例时实际发生的情况——它是什么?我可以看到这两种键类型之间的主要区别是一种具有有限的值集,另一种具有无限的值集。这是用来区分的吗?
除此之外,我能找到的唯一解释是 Record 不仅根据其键类型的值集进行区分,而且还根据其键类型的一些其他属性进行区分。如果是这样,键类型的什么属性会有所不同?还是 Record 做了相当于“绕过接口,转换为实现类型并做一些你不应该做的事情”的类型系统?
Record的实现是
type Record<K extends keyof any, T> = {
[P in K]: T;
};
我可以在这里发现两件事。第一个是将 K 绑定到“任意键”,但据我所知,这限制了可用于 K 的类型,而不是对结果类型有效的值。其次,我们有一个正常的索引签名,所以我的猜测是,我在 Record 中感到困惑的实际上是索引签名的行为——但由于其他问题,如果没有 Record,我无法轻松重现这种行为,所以我没有不想妄下结论。
【问题讨论】:
标签: typescript types record