为何使用Spread operator时TypeScript无额外属性警告?
TypeScript中扩展运算符为何能避免额外属性警告?
你遇到的情况是:两段使用扩展运算符(...)的代码都能通过TypeScript编译,不会触发「Object literal may only specify known properties, and 'b' does not exist in type 'A'」的警告,但如果移除扩展语句,直接传对象字面量就会报错。
两段示例代码如下:
第一段代码:
type A = { a: string; }; function withA(a: A) {} const test = (message: {b: number}) => { withA({ ...message, // 此处的扩展运算符 a: 'foo', }); };
第二段代码:
type A = { a: string; }; function withA(a: A) {} const test = <T>(message: T) => { withA({ ...message, b: 'bar', // 额外的b属性 a: 'foo', }); };
这本质是TypeScript对对象字面量的额外属性检查规则导致的。
TypeScript在直接传递对象字面量给函数参数时,会启用严格的额外属性检查——只要字面量里有目标类型没定义的属性,就会报错。但如果这个对象不是直接的字面量,而是通过扩展运算符构建出来的「非字面量对象」,TypeScript就不会触发这个额外检查。
具体来说:
- 当你写
withA({ a: 'foo', b: 123 })时,这是直接传对象字面量,TypeScript会严格比对A的类型,发现b不在A里,直接报错。 - 但当你用
...message扩展后,构建出来的对象会被TypeScript视为一个「普通对象表达式」,而非「新鲜的对象字面量」,此时只会做结构类型兼容性检查——只要这个对象包含A要求的所有属性(这里就是a: string),就认为符合类型要求,多余的属性会被忽略,不会触发警告。
另外第二段代码里,message是泛型T,扩展后加上b和a,最终的对象类型是T & { b: string; a: string },这个类型和A是结构兼容的(因为包含了a: string),所以同样不会触发额外属性检查。
简单总结:直接传对象字面量会触发额外属性检查,用扩展运算符构建的对象则只会走常规的结构类型兼容判断,多余属性不会被报错。
内容的提问来源于stack exchange,提问作者Teebs
相关产品推荐
相关产品推荐

