如何实现递归修改TypeScript函数重载返回类型的工具类型
问题描述
我在一个库中有一个带多个函数重载的接口,希望修改该类型中所有函数签名的返回类型。原接口定义如下:
interface Chainer<Subject> { (chainer: 'be.a', type: string): Cypress.Chainable<Subject> (chainer: 'be.above', value: number | Date): Cypress.Chainable<Subject> // ... 此处还有更多重载 }
我编写的工具类型仅能处理单个函数签名,无法覆盖所有重载:
// 预期修改返回类型的工具类型 type RemapFunctionReturnType<T, U> = T extends (...args: infer P) => any ? (...args: P) => U : never; type ModifiedChainer = RemapFunctionReturnType<Chainer<any>, number>; // 期望实现的效果:所有返回类型改为number // interface ModifiedChainer<Subject> { // (chainer: 'be.a', type: string): number; // (chainer: 'be.above', value: number | Date): number; // // ... 此处还有更多重载 // }
我尝试了递归版本,但仍仅支持单个签名,需要实现能处理所有重载的递归工具类型:
type RemapFunctionReturnType<T, U> = T extends (...args: infer P) => any & infer Next ? (...args: P) => U | RemapFunctionReturnType<Next, U> : never;
解决方案
可以通过递归遍历并合并所有重载签名的方式实现,正确的工具类型如下:
type RemapFunctionReturnType<T, U> = T extends (...args: infer P) => infer R ? ((...args: P) => U) & RemapFunctionReturnType<Exclude<T, (...args: P) => R>, U> : {};
原理说明
- 匹配函数签名:通过条件类型判断
T是否为函数类型,提取参数列表P和原返回类型R - 替换返回类型:将当前函数签名的返回类型替换为目标类型
U - 递归处理剩余重载:使用
Exclude<T, (...args: P) => R>移除已经处理过的签名,递归处理剩余的重载 - 终止条件:当没有剩余签名可处理时,返回空对象
{},避免多余的类型合并
使用示例
// 生成修改后的类型 type ModifiedChainer<Subject> = RemapFunctionReturnType<Chainer<Subject>, number>; // 此时 ModifiedChainer 的所有重载返回类型均为 number,符合预期
内容的提问来源于stack exchange,提问作者Michael Stoltz
相关产品推荐
相关产品推荐

