TypeScript扩展运算符异常:空映射类型致校验失效如何修复?
问题修复方案
问题根源
当third接口继承base且无额外属性时,Omit<third, keyof base>会得到空类型{}。此时MappedTypeFunc<{}, any>生成的thirdMapped也是空类型,导致thirdFullMapped = baseMapped & {}等价于baseMapped。TypeScript仅对有明确属性定义的类型执行额外属性检查,空类型不会限制多余属性,因此firstObject的firstProp能被混入thirdObjectFull而不触发错误。
修复方案
我们需要让thirdFullMapped在继承baseMapped的同时,明确禁止任何不属于baseMapped的额外属性。通过自定义辅助类型实现这一约束:
步骤1:定义严格组合类型
创建StrictCombine类型,自动处理空扩展类型的场景,为空扩展类型添加禁止额外属性的约束:
type StrictCombine<Base, Extension> = Extension extends {} ? Base & Extension : Base & Record<Exclude<keyof any, keyof Base>, never>;
逻辑说明:如果Extension是空类型,则返回Base加上“禁止所有非Base属性”的索引签名;否则返回正常的交叉类型。
步骤2:替换原有FullMapped类型定义
用StrictCombine替代原有的交叉类型定义,统一处理所有场景:
type firstFullMapped = StrictCombine<baseMapped, firstMapped>; type secondFullMapped = StrictCombine<baseMapped, secondMapped>; type thirdFullMapped = StrictCombine<baseMapped, thirdMapped>;
完整修复代码
interface base { type: string; name: string; add: string; } interface first extends base { firstProp: string } interface second extends base { secondProp: string } interface third extends base { } type MappedTypeFunc<T, U> = { [K in keyof T]: (value: T[K], additionalParam?: U) => any; } type baseMapped = MappedTypeFunc<base, any> type firstMapped = MappedTypeFunc<Omit<first, keyof base>, any> type secondMapped = MappedTypeFunc<Omit<second, keyof base>, any> type thirdMapped = MappedTypeFunc<Omit<third, keyof base>, any> // 新增严格组合辅助类型 type StrictCombine<Base, Extension> = Extension extends {} ? Base & Extension : Base & Record<Exclude<keyof any, keyof Base>, never>; // 使用StrictCombine定义完整类型 type firstFullMapped = StrictCombine<baseMapped, firstMapped>; type secondFullMapped = StrictCombine<baseMapped, secondMapped>; type thirdFullMapped = StrictCombine<baseMapped, thirdMapped>; const baseObject: baseMapped = { type: function (value: string, additionalParam?: any) { throw new Error("Function not implemented."); }, name: function (value: string, additionalParam?: any) { throw new Error("Function not implemented."); }, add: function (value: string, additionalParam?: any) { throw new Error("Function not implemented."); } } const firstObject: firstMapped = { firstProp: function (value: string, additionalParam?: any) { throw new Error("Function not implemented."); } } const secondObject: secondMapped = { secondProp: function (value: string, additionalParam?: any) { throw new Error("Function not implemented."); } } const thirdObject: thirdMapped = {} const firstObjectFull: firstFullMapped = { ...baseObject, ...firstObject } // 依然报错(符合预期) const secondObjectFull: secondFullMapped = { ...baseObject, ...firstObject } // 现在会触发类型错误:firstProp属性不存在于thirdFullMapped类型中 const thirdObjectFull: thirdFullMapped = { ...baseObject, ...firstObject }
效果验证
修复后,thirdObjectFull混入firstObject时,TypeScript会检测到firstProp为多余属性,触发预期的类型错误,与secondObjectFull的行为保持一致。
内容的提问来源于stack exchange,提问作者Andrew M
相关产品推荐
相关产品推荐

