如何使用泛型定义支持异步操作的简易Pipe函数?
实现带类型推导的异步/同步兼容Pipe函数
你的核心问题是单个泛型无法覆盖管道中每一步的类型传递——管道里的每个步骤要么是直接值(会覆盖前一步结果),要么是函数(接收前一步的解包值,返回新结果),需要用递归泛型+条件类型来实现准确的类型推断。
完整实现代码
// 辅助类型:解包Promise类型,获取内部值的类型 type Unwrap<T> = T extends Promise<infer U> ? U : T; // 递归类型:计算管道执行后的最终返回类型 type PipeReturn<Args extends any[]> = Args extends [infer First] ? First // 只有一个参数时,直接返回该参数的类型 : Args extends [...infer Rest, infer Last] ? Last extends (value: Unwrap<PipeReturn<Rest>>) => infer Output ? Output // 最后一步是函数时,返回函数的输出类型 : Last // 最后一步是值时,返回该值的类型 : never; export const pipe = <Args extends any[]>(...args: Args): PipeReturn<Args> => { return args.reduce((prev, exec) => { if (typeof exec !== 'function') { // 非函数值直接覆盖前一步结果 return exec; } // 处理异步/同步逻辑:如果前一步是Promise,用then链式调用;否则直接执行函数 return prev instanceof Promise ? prev.then(exec) : exec(prev); }) as PipeReturn<Args>; };
代码解释
- Unwrap类型:用来提取Promise内部的类型,比如
Unwrap<Promise<number>>会得到number,非Promise类型则直接返回自身。 - PipeReturn类型:递归推导管道的最终返回类型:
- 如果只有一个参数,直接返回该参数的类型;
- 如果有多个参数,先推导前面所有步骤的结果类型,再判断最后一步是函数还是值:
- 是函数时,函数的参数类型为前面步骤结果的解包类型,返回函数的输出类型;
- 是值时,直接返回该值的类型。
- pipe函数逻辑:简化了原实现的异步处理,直接通过
instanceof Promise判断前一步结果类型,避免了多余的async函数嵌套,同时保持原有的行为。 - 类型断言:由于TypeScript对reduce的递归类型推断能力有限,最后用
as PipeReturn<Args>断言返回类型,确保类型推导准确。
测试示例
// 示例1:纯值传递 const res1 = pipe(1, "hello", true); // res1类型:boolean // 示例2:同步函数 const res2 = pipe(10, (x) => x * 2); // res2类型:number(值为20) // 示例3:异步函数 const res3 = pipe(5, (x) => Promise.resolve(x + 3)); // res3类型:Promise<number>(值为8) // 示例4:混合异步值和函数 const res4 = pipe(Promise.resolve(100), (x) => x / 2); // res4类型:Promise<number>(值为50) // 示例5:混合值和函数 const res5 = pipe("test", "hello world", (str) => str.length); // res5类型:number(值为11)
内容的提问来源于stack exchange,提问作者sir-haver
相关产品推荐
相关产品推荐

