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

如何递归排除TypeScript两个类型间的公共属性?

递归排除TypeScript类型的公共属性并保留可选性

要实现递归排除两个类型的公共属性,同时保留原类型的可选属性修饰符,可使用以下类型工具:

// 辅助类型:判断是否为普通对象(排除数组、函数、日期等特殊类型)
type IsObject<T> = T extends object 
  ? T extends Array<any> | Function | Date | RegExp 
    ? false 
    : true 
  : false;

// 核心递归类型:排除与K共有的属性,递归处理嵌套对象,保留可选性
type ExcludeCommonRecursively<T, K> = {
  // 通过Pick+Exclude筛选需保留的键,自动保留原属性的可选修饰符
  [U in keyof Pick<T, Exclude<keyof T, keyof K>>]: 
    // 若属性值为普通对象,递归处理;数组则递归处理元素类型,否则直接保留原类型
    IsObject<T[U]> extends true 
      ? ExcludeCommonRecursively<T[U], K> 
      : T[U] extends Array<infer V> 
        ? IsObject<V> extends true 
          ? ExcludeCommonRecursively<V, K>[] 
          : T[U] 
        : T[U];
};

验证结果

用你提供的示例类型测试:

type One = {
  one: number;
  two?: number;
  three: number;
  sub: {
    two?: number;
    three: number;
  }
}

type Two = {
  three: number;
}

type Three = ExcludeCommonRecursively<One, Two>;

生成的Three类型与期望完全一致:

type Three = {
  one: number;
  two?: number;
  sub: {
    two?: number;
  }
}

之前实现的问题分析

非递归版本的局限

非递归的ExcludeType仅处理顶层属性,无法深入嵌套对象内部排除公共属性,因此sub中的three未被移除。

原递归版本的问题

  1. 键排除逻辑错误:原代码中Exclude<keyof T, keyof U>是笔误,应改为Exclude<keyof T, keyof K>,否则无法正确排除与K共有的属性。
  2. 丢失可选属性修饰符:直接使用[U in ...]映射时,会丢失原属性的?修饰符;通过Pick<T, Exclude<keyof T, keyof K>>先筛选键再映射,可自动保留可选性。
  3. 对象判断逻辑错误:原代码中T[U] extends U的判断逻辑完全错误,需通过IsObject明确区分普通对象与其他类型。

扩展说明

  • IsObject类型默认排除了数组、函数等特殊对象,若需处理这些类型,可调整其判断逻辑。
  • 实现支持数组元素的递归处理:若数组元素为对象,会自动排除其与K共有的属性。

内容的提问来源于stack exchange,提问作者Yokozuna59

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 09:02:32