如何强制TypeScript对扩展创建的对象进行类型检查?
问题原因
TypeScript 对直接编写的对象字面量会触发「额外属性检查」,但对通过展开表达式(...)合并变量得到的对象,不会触发该检查——因为它认为你是有意合并已有变量的属性,而非误写了额外字段。这就是为什么显式添加不存在的字段会报错,但展开其他类型对象不会的原因。
解决方法
以下是几种让 TypeScript 对这种场景执行类型检查的实用方案:
方案1:先合并到变量再赋值
先将合并后的对象赋值给一个变量,让 TypeScript 推导出它的完整类型,再赋值给目标类型变量。此时会触发正常的类型兼容性检查,因为合并后的类型包含目标类型没有的属性,会直接报错:
type TypeA = { id: number; } type TypeB = { name: string; } const a: TypeA = { id: 3 }; const b: TypeB = { name: 'my' }; const merged = { ...a, ...b }; // 类型被推导为 TypeA & TypeB const c: TypeA = merged; // 报错:类型 "TypeA & TypeB" 中属性 "name" 不在类型 "TypeA" 中
方案2:使用辅助函数强制检查
创建一个接受严格符合目标类型参数的辅助函数,传入合并后的对象时,会触发额外属性检查:
type TypeA = { id: number; } type TypeB = { name: string; } const a: TypeA = { id: 3 }; const b: TypeB = { name: 'my' }; function strictAssign<T>(obj: T): T { return obj; } const c = strictAssign<TypeA>({ ...a, ...b, }); // 报错:对象文字可以只指定已知属性,并且“name”不在类型“TypeA”中
方案3:自定义Exact类型约束
如果需要更严格的类型匹配(确保目标对象没有任何额外属性),可以自定义一个Exact工具类型,强制合并后的类型与目标类型完全一致:
type Exact<T, U> = T extends U ? (U extends T ? T : never) : never; type TypeA = { id: number; } type TypeB = { name: string; } const a: TypeA = { id: 3 }; const b: TypeB = { name: 'my' }; const merged = { ...a, ...b }; const c: Exact<TypeA, typeof merged> = merged; // 报错:类型 "TypeA & TypeB" 不能赋值给类型 "never"
内容的提问来源于stack exchange,提问作者Joy
相关产品推荐
相关产品推荐

