TypeScript实现按键值类型匹配过滤属性的自定义Omit工具类型
TypeScript 实现按类型匹配剔除属性的工具类型
OmitWithTypeMatch 需求规则
- 接收两个接口类型A、B
- 仅当两个接口存在同名键且对应值类型完全匹配时,才从A中移除该键
- A中其余属性全部保留:包括键名相同但类型不匹配的属性、仅在A中存在的属性
问题复现
直接使用TS内置Omit类型无法满足需求,内置Omit只会按键名匹配剔除属性,不会校验值类型是否一致:
// 内置Omit的效果:会把所有B中存在的同名键全部移除 type ResultingCar = Omit<Car, keyof OtherTypeOfCar>; // 最终仅保留driver属性,wheels、doors都会被错误移除 const car2: ResultingCar = { driver: 1, };
实现方案
TS 4.1及以上版本可通过映射类型键重映射语法+严格类型相等判断实现,完整代码如下:
// 严格判断两个类型是否完全相等的辅助类型,避免extends带来的子类型兼容误判 type Equal<X, Y> = (<T>() => T extends X ? 1 : 2) extends (<T>() => T extends Y ? 1 : 2) ? true : false type OmitWithTypeMatch<A, B> = { [K in keyof A as K extends keyof B ? Equal<A[K], B[K]> extends true ? never : K : K ]: A[K] }
效果验证
使用题目给出的示例校验:
interface Car { wheels: number; doors: number; driver: number; } interface OtherTypeOfCar { wheels: number; // 键名、类型均匹配,会被移除 doors: string; // 键名相同但类型不匹配,保留 windows: string; // 仅在B中存在,不影响A的属性 } type ResultingCar = OmitWithTypeMatch<Car, OtherTypeOfCar>; // 符合预期:仅wheels被移除,doors、driver正常保留 const car1: ResultingCar = { doors: 5, driver: 1, };
实现逻辑说明
- 核心依赖TS 4.1新增的映射类型
as键重映射能力,遍历A的属性键时直接完成过滤 - 遍历A的每个键K时,先判断K是否存在于B的键集合中:
- 不存在:直接保留该键
- 存在:通过
Equal辅助类型做严格类型一致性校验,类型完全相等则返回never剔除该键,否则保留
- 没有直接使用
A[K] extends B[K]做判断,是为了避免子类型兼容、any类型特殊规则带来的误匹配,保证只有完全相同的类型才会触发剔除。
内容的提问来源于stack exchange,提问作者Konstantin Paulus
相关产品推荐
相关产品推荐

