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

TypeScript中如何递归根据指定对象过滤字段并定义返回类型?

递归剔除对象字段并实现TypeScript类型推导

是否可以根据另一个对象中指定的字段,递归地剔除目标对象中的对应字段?我希望指定API调用需获取的字段,同时让TypeScript正确推导返回值类型(剔除未指定的字段),示例代码如下:

interface Person {
  head: {
    hairColor: string
    eyeColor: string
  }
}

const person: Person = {
  head: {
    hairColor: 'gray',
    eyeColor: 'green',
  }
}

// 递归将对象所有值转为布尔类型
type BooleanValues<T> = {
  [K in keyof T]?: T[K] extends object ? BooleanValues<T[K]> : boolean
}

const fieldsToInclude: BooleanValues<Person> = {
  head: {
    hairColor: true,
    // 无需指定false值,未指定字段默认视为false并被剔除
  }
}

dropFields(person, fieldsToInclude)

function dropFields<T>(x: T, y: BooleanValues<T>): IncludeFieldsBasedOn<T, typeof y> {
  return // ... 待实现逻辑
}

我尝试了如下写法定义IncludeFieldsBasedOn<T, U>,但因类型错误无法运行:

type IncludeFieldsBasedOn<T, O extends BooleanValues<T>> = {
  [K in keyof T]: T[K] extends object ? IncludeFieldsBasedOn<T[K], O[K]> : O[K] extends true ? T[K] : never
}

问题在于该写法无法识别O[K]与T类型的匹配关系。


正确的类型定义与实现

1. 修正IncludeFieldsBasedOn类型

核心思路是提取配置对象中显式设为true的键,再递归处理嵌套对象的字段筛选:

// 递归提取配置对象中值为true的键
type ExtractTrueKeys<U> = {
  [K in keyof U]: U[K] extends true 
    ? K 
    : U[K] extends object 
      ? ExtractTrueKeys<U[K]> extends infer SubKeys 
        ? SubKeys extends never 
          ? never 
          : K 
        : never 
      : never
}[keyof U]

// 根据配置生成仅包含指定字段的类型
type IncludeFieldsBasedOn<T, U> = 
  T extends object 
    ? {
        [K in ExtractTrueKeys<U> & keyof T]: 
          T[K] extends object 
            ? U[K] extends object 
              ? IncludeFieldsBasedOn<T[K], U[K]> 
              : T[K]
            : T[K]
      }
    : T

2. 实现dropFields函数

配合类型定义,编写递归剔除字段的逻辑:

function dropFields<T, U extends BooleanValues<T>>(x: T, y: U): IncludeFieldsBasedOn<T, U> {
  if (typeof x !== 'object' || x === null) {
    return x as IncludeFieldsBasedOn<T, U>
  }

  const result = {} as IncludeFieldsBasedOn<T, U>
  for (const key in y) {
    const configValue = y[key]
    // 直接保留设为true的字段
    if (configValue === true) {
      (result as any)[key] = x[key as keyof T]
    } 
    // 递归处理嵌套对象的字段筛选
    else if (typeof configValue === 'object' && configValue !== null) {
      const nestedResult = dropFields(x[key as keyof T], configValue as BooleanValues<T[keyof T]>)
      // 仅保留有有效字段的嵌套对象
      if (Object.keys(nestedResult).length > 0) {
        (result as any)[key] = nestedResult
      }
    }
  }
  return result
}

类型验证

调用dropFields(person, fieldsToInclude)后,TypeScript会自动推导返回值类型为:

{
  head: {
    hairColor: string
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 13:35:56