为何TypeScript中扩展语法(...)不遵循返回类型的类型安全性?
问题解析:扩展语法添加非法键未触发TypeScript报错
核心原因:不是Bug,是类型检查机制差异
你遇到的情况是TypeScript的设计行为——关键在于TypeScript对「直接对象字面量」和「扩展语法组合的对象」采用了不同的检查规则:
直接对象字面量会触发「多余属性检查」
当你直接在返回的对象字面量里写wut: 'somewut'时,TypeScript会启动专门针对对象字面量的额外校验:如果字面量包含目标类型(这里是Partial<Record<Value, string>>)中未定义的属性,就会抛出错误。这是TypeScript为避免拼写错误或意外添加属性设计的保护机制。扩展语法不会触发多余属性检查
当你用...({wut: 'somewut'})时,被扩展的{wut: 'somewut'}是一个独立表达式,TypeScript会先将其推断为普通的{wut: string}类型。这个类型和前面的对象合并后,得到Partial<Record<Value, string>> & {wut: string}类型。而TypeScript的结构类型系统允许子类型赋值给父类型——合并后的类型包含了目标类型的所有属性,还多了
wut,属于目标类型的子类型,因此编译器认为它可以安全赋值给返回类型,不会报错。
解决方案:强制限制扩展对象的类型
如果你想让编译器检测到这类非法属性,可以显式约束被扩展对象的类型,比如:
方案1:使用satisfies关键字(TypeScript 4.9+)
type Value = 'foo'| 'bar'| 'baz'; const getValues = (): Partial<Record<Value, string>> => { return { foo: 'someFoo', baz: 'someBaz', ...({wut: 'somewut'} satisfies Partial<Record<Value, string>>) } }
编译器会直接检查被扩展对象是否符合目标类型,非法属性会立刻报错。
方案2:类型断言(兼容旧版本)
type Value = 'foo'| 'bar'| 'baz'; const getValues = (): Partial<Record<Value, string>> => { return { foo: 'someFoo', baz: 'someBaz', ...({wut: 'somewut'} as Partial<Record<Value, string>>) } }
通过断言指定被扩展对象的类型,非法属性会触发断言错误。
内容的提问来源于stack exchange,提问作者ThePuzzleMaster
相关产品推荐
相关产品推荐

