[英]Why does type Record sometimes complain about missing keys and sometimes not?
考虑以下代码:
const testOne: Record<"foo"|"bar", string> = {
"foo": "xyz"
};
const testTwo: Record<string, string> = {
"foo": "xyz"
};
第一个示例导致属性“bar”丢失的错误。 第二个示例不会导致错误。 这让我感到困惑,因为我试图了解 Record 是否是一种类型,它暗示了其键类型的所有可能值的现有属性。
如果 Record 是一种不要求所有可能的键实际存在于该类型的值中的类型,那么第一个示例不应导致错误。
如果 Record是一种类型,它要求所有可能的键实际存在于该类型的值中,那么第二个示例也应该导致错误。 在这种情况下,不可能构造该类型的值,因为可能的键集是无限的。
如果有第三种选择——根据我尝试编译示例时实际发生的情况,似乎有第三种选择——它是什么? 我可以看到两种键类型之间的主要区别在于,一种具有有限的值集,另一种具有无限的值集。 这是用来区分的吗?
除此之外,我能找到的唯一解释是 Record 不仅基于其键类型的值集,而且还基于其键类型的一些其他属性进行区分。 如果是这样,密钥类型的哪些属性会有所不同? 或者 Record 做的类型系统相当于“绕过接口,转换为实现类型并做一些你不应该做的事情”?
Record的实现是
type Record<K extends keyof any, T> = {
[P in K]: T;
};
我可以在这里发现两件事。 第一个是 K 与“keyof any”的绑定,但据我所知,这限制了 K 可以使用的类型,而不是对结果类型有效的值。 其次,我们有一个正常的索引签名,所以我的猜测是我在 Record 中感到困惑的实际上是索引签名的行为——但是由于其他问题,我无法在没有 Record 的情况下轻松重现这种行为,所以我不不想妄下结论。
让我们从实现开始:
type Record<K extends keyof any, T> = {
[P in K]: T;
};
keyof any
- 仅表示可用作任何对象的键的所有允许类型。 现在,为此您可以使用内置类型的PropertyKey
。
{[P in K]: T;}
这只是一个常规的for..in
循环。
因此,当您将联合类型"foo"|"bar"
作为第一个参数传递给Record
,TS 编译器只会遍历每个联合并创建如下所示的 smth:
type Result = {
foo:string,
bar: string,
}
这意味着您的最终对象应该具有最少的属性集: foo
和bar
。
但是,当您仅将string
作为第一个参数传递时,情况就不同了。
type Result = Record<string, string>
type Result2 = {
[P in string]: string
}
您可能已经注意到, Result
和Result2
是相同的类型。
现在,您可能认为Record<string, string>
等于索引接口:
interface Indexed {
[prop: string]: string
}
type Result = Record<string, string>
type Check = Result extends Indexed ? true : false // true
type Check2 = Indexed extends Result ? true : false // true
但是这些类型的行为有点不同。 看到这个答案
更新
问题似乎仍然是 Record 是否要求所有可能的属性都实际存在。 如果 Record 不要求所有可能的属性实际存在,为什么结果是具有必填字段而不是可选字段的对象类型?
请参阅映射类型文档
从文档:
映射类型建立在索引签名的语法之上,用于声明尚未提前声明的属性类型:
因此,类型Record<string, string>
意味着您不确切知道将用于记录的键,但您 100% 确定它将是string
。 这是设计使然。
为什么Partial<Record<string, string>>
与Record<string, string>
,因为Partial
意味着值也可以是undefined
。
换句话说, Partial<Record<string, string>>
等于Record<string,string | undefined>
Record<string,string | undefined>
它如何适用于“inifite”类型,例如字符串
这意味着如果 key 是string
类型,则可以使用任何字符串来完成此要求。 没有任何无穷大的字符串集。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.