原始对象和扩展对象之间的TypeScript差异



关于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中发生更多活动,否则目前还没有一个非常令人满意的答案。

最新更新