You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 19:45:31