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

如何实现递归筛选函数/含函数对象的TypeScript工具类型

实现TypeScript工具类型筛选API中的函数及含函数的嵌套对象

直接上可运行的工具类型实现,再拆解逻辑:

// 判断是否为函数类型
type IsFunction<T> = T extends (...args: any[]) => any ? true : false;

// 递归判断类型是否自身是函数,或是包含函数的对象
type HasFunction<T> = 
  // 自身是函数直接返回true
  IsFunction<T> extends true ? true :
  // 是对象的话,检查所有属性里是否有含函数的
  T extends object ? (
    { [K in keyof T]: HasFunction<T[K]> }[keyof T] extends true ? true : false
  ) : false;

// 核心过滤工具:只保留符合条件的属性,并递归处理嵌套对象
type FilterApi<T extends object> = {
  [K in keyof T as HasFunction<T[K]> extends true ? K : never]:
    // 如果是函数直接保留类型
    IsFunction<T[K]> extends true ? T[K] :
    // 如果是对象,递归过滤
    T[K] extends object ? FilterApi<T[K]> :
    never;
};

逻辑拆解

  1. IsFunction:最基础的函数类型判断,把函数类型和其他类型区分开。
  2. HasFunction:递归检查逻辑——如果当前类型是函数直接通过;如果是对象,遍历它的所有属性,只要有一个属性满足“含函数”的条件,整个对象就符合保留要求;其他类型(比如数字、纯数组)直接排除。
  3. FilterApi:利用TypeScript的键重映射特性,把不满足HasFunction的属性直接剔除。对于保留的属性,如果是函数就原样保留类型,是对象的话继续递归过滤,确保嵌套结构里的非函数字段也被清理掉。

示例验证

用你提供的API对象测试:

const api = {
  args: ["hello", "stackoverflow"],
  pid: 5,
  hack: (server: string): void => { console.log("hack server"); },
  stanek: {
      charge: (id: number): number => {
        console.log("charge");
        return 5;
      },
      width: 5,
      height: 5,
  },
  gang: {
    power: {
      do: () => undefined,
    },
  },
  enums: {
    factions: ["a", "b"],
  },
};

type ApiType = typeof api;
type FilteredApi = FilterApi<ApiType>;

此时FilteredApi的类型完全符合你的预期:

interface FilteredApi {
  hack: (server: string) => void;
  stanek: {
    charge: (id: number) => number;
  };
  gang: {
    power: {
      do: () => undefined;
    };
  };
}

注意事项

  • 纯数组(不含函数的数组)会被直接过滤,比如示例里的args和enums.factions对应的属性都会被剔除。
  • 嵌套对象会递归处理到最底层,只保留包含函数的分支,像stanek里的width、height这类非函数字段会被自动清理。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 14:57:14