如何实现递归筛选函数/含函数对象的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; };
逻辑拆解
- IsFunction:最基础的函数类型判断,把函数类型和其他类型区分开。
- HasFunction:递归检查逻辑——如果当前类型是函数直接通过;如果是对象,遍历它的所有属性,只要有一个属性满足“含函数”的条件,整个对象就符合保留要求;其他类型(比如数字、纯数组)直接排除。
- 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
相关产品推荐
相关产品推荐

