关于Typescript有一个我无法理解的谜题:
const randomFn = (arg: Record<string, unknown>): string => 'kappa'
export type Values = {
key: string;
};
const values: Values = {
key: 'kappa'
}
const { ...spread } = values;
randomFn(values)
randomFn(spread) // produce Index signature for type 'string' is missing in type '{ transaction: string; }'.(2345)
为什么Typescript会为spread对象产生错误,而在我的理解中,它的键入应该是相同的。如果我们在操场上检查对象,它对TS编译器来说是完全一样的。既有原创的,也有传播的。
TS版本4.5.4。打字游戏场中的复制
编辑:也做双重传播,使其再次工作
randomFn({...spread}) // NO error
Spreading会丢失类型,因为它无法保证spread对象的类型相同。考虑一下:
const { excluded, ...rest } = object;
显然,rest
不可能是与object
相同的类型;少了一把钥匙!
你也可以这样想:
const [excluded, ...rest] = array;
这就是为什么spread
不是类型Values
。
这是TypeScript设计限制的结果,有关详细信息,请参阅microsoft/TypeScript#42021。不幸的是,当您在对象析构函数赋值中使用rest元素时,TypeScript不会将索引签名复制到新变量的类型中。它也不允许变量具有隐式索引签名(尽管我不确定为什么(。
允许您的Values
类型别名具有隐式索引签名(如果您将其设为interface
,则它也不会,请参阅microsoft/TypeScript#15300(,因此它被认为可分配给Record<string, unknown>
(相当于具有字符串索引签名的类型{[k: string]: unknown}
(。但spread
作为一个rest析构函数变量,却不是,因此它失败了。
您注意到,执行第二个rest destructuring确实有效,所以对象类型被标记为允许或不允许隐式索引签名可能有些奇怪。这一点在microsoft/TypeScript#42021中也有说明,尽管没有解释。
因此,不幸的是,除非在microsoft/TypeScript#42021中发生更多活动,否则目前还没有一个非常令人满意的答案。