如何递归替换TypeScript中函数、数组等类型的指定类型?
递归替换TypeScript嵌套类型中的指定类型(支持函数、数组、元组、泛型容器)
需求说明
之前的类型替换方案无法覆盖所有场景,需要实现一个能递归处理嵌套结构的类型工具:
- 替换函数的参数和返回值中的指定类型
- 保留数组、元组的结构特性,替换其元素类型
- 支持Promise、Set、Map这类泛型容器的内部类型替换
- 递归处理对象的嵌套属性
测试用例
type Foo = { bar(x: number, y: string): string baz: { a(): string b: [string, string] c: string[] }, bing: Promise<string> boom: Set<string> bah: { a: Map<number, string> b: Map<string, string> c: Map<string, number> } }; type Bar = ReplaceTypes<Foo, string, "inky" | "pinky" | "blinky" | "clyde">; var x: Bar;
预期输出
var x: { bar: (x: number, y: "inky" | "pinky" | "blinky" | "clyde") => "inky" | "pinky" | "blinky" | "clyde"; baz: { a: () => "inky" | "pinky" | "blinky" | "clyde"; b: ["inky" | "pinky" | "blinky" | "clyde", "inky" | "pinky" | "blinky" | "clyde"]; c: ("inky" | "pinky" | "blinky" | "clyde")[]; }; bing: Promise<"inky" | "pinky" | "blinky" | "clyde">; boom: Set<"inky" | "pinky" | "blinky" | "clyde">; bah: { a: Map<number, "inky" | "pinky" | "blinky" | "clyde">; b: Map<"inky" | "pinky" | "blinky" | "clyde", "inky" | "pinky" | "blinky" | "clyde">; c: Map<"inky" | "pinky" | "blinky" | "clyde", number>; } }
实现方案
完全可行,通过TypeScript的条件类型、递归类型以及内置工具类型可以实现该需求,以下是完整的ReplaceTypes类型工具:
type ReplaceTypes<T, From, To> = // 基础类型直接替换 T extends From ? To : // 处理函数类型:替换参数和返回值 T extends (...args: infer Args) => infer Return ? (...args: ReplaceTypes<Args, From, To>) => ReplaceTypes<Return, From, To> : // 处理元组类型:保留元组结构,替换每个元素 T extends readonly [infer First, ...infer Rest] ? [ReplaceTypes<First, From, To>, ...ReplaceTypes<Rest, From, To>] : // 处理数组类型:替换元素类型 T extends Array<infer U> ? Array<ReplaceTypes<U, From, To>> : // 处理Promise:替换泛型参数 T extends Promise<infer U> ? Promise<ReplaceTypes<U, From, To>> : // 处理Set:替换泛型参数 T extends Set<infer U> ? Set<ReplaceTypes<U, From, To>> : // 处理Map:替换键和值的类型 T extends Map<infer K, infer V> ? Map<ReplaceTypes<K, From, To>, ReplaceTypes<V, From, To>> : // 处理对象类型:递归替换每个属性 T extends object ? { [K in keyof T]: ReplaceTypes<T[K], From, To> } : // 其他类型直接返回 T;
代码解释
- 基础类型替换:优先匹配要替换的目标类型,直接返回新类型
- 函数类型处理:通过
infer提取参数列表和返回值,分别递归替换后重新构造函数类型 - 元组类型处理:用
readonly [infer First, ...infer Rest]匹配元组结构,逐个替换元素后保留元组形态 - 数组类型处理:匹配数组并提取元素类型,替换后重新构造数组类型
- 泛型容器处理:分别处理Promise、Set、Map这类常见泛型容器,替换其内部的泛型参数
- 对象类型处理:遍历对象的所有键,递归替换每个属性的类型
- 兜底逻辑:未匹配到上述类型的,直接返回原类型
将该类型工具应用到测试用例中,即可得到预期的输出结果,完全满足递归替换嵌套类型且保留原有类型特性的需求。
内容的提问来源于stack exchange,提问作者dragoncoder047
相关产品推荐
相关产品推荐

