能否保留重载函数的参数签名仅修改其返回类型?
如何修改重载函数的返回类型同时保留原参数签名?
我有一个接受P个参数、返回类型为R的函数,希望保留原有的P个参数签名,但将返回类型改为Z。对于普通函数,可以用Parameters工具类型实现:
const foo = (s: string, n: number) => s type Bar = (...test: Parameters<typeof foo>) => number declare const bar: Bar foo('s', 1) // 返回 string bar('s', 1) // 返回 number
但对于存在重载的函数,Parameters工具类型无法正常工作:
function foo1(a: string): string; function foo1(a: string, b: number): string; function foo1(a: string | number, b?: number) { return 'string' } type Bar1 = (...test: Parameters<typeof foo1>) => number declare const bar1: Bar1 foo1('s') // 返回 string foo1('s', 1) // 返回 string bar1('s') // 类型错误(因为Parameters取的是实现签名的参数类型,要求第二个参数可选但类型为number,传入's'不匹配) bar1('s', 1) // 返回 number
解决方案:自定义工具类型处理重载签名
Parameters只会提取函数的实现签名(即带函数体的那个签名),而重载函数对外暴露的是前面的多个签名。我们可以自定义工具类型来匹配每个重载签名,替换返回类型后交叉合并:
// 自定义工具类型:替换函数(包括重载)的返回类型 type ReplaceReturnType<T, NewReturn> = // 匹配单签名函数 T extends (...args: infer Args) => infer _ ? (...args: Args) => NewReturn // 匹配双重载签名 : T extends { (...args: infer Args1): infer _; (...args: infer Args2): infer _ } ? ((...args: Args1) => NewReturn) & ((...args: Args2) => NewReturn) // 匹配三重载签名,可按需扩展更多分支 : T extends { (...args: infer Args1): infer _; (...args: Args2): infer _; (...args: Args3): infer _ } ? ((...args: Args1) => NewReturn) & ((...args: Args2) => NewReturn) & ((...args: Args3) => NewReturn) : never; // 应用到重载函数 function foo1(a: string): string; function foo1(a: string, b: number): string; function foo1(a: string | number, b?: number) { return 'string' } type Bar1 = ReplaceReturnType<typeof foo1, number>; declare const bar1: Bar1; bar1('s'); // 正常,返回 number bar1('s', 1); // 正常,返回 number
原理说明
这个工具类型通过条件分支匹配不同数量的重载签名,分别提取每个签名的参数类型,替换返回类型为目标类型NewReturn,最后将所有修改后的签名交叉合并,从而完整保留原函数的所有重载参数签名,同时统一修改返回类型。如果需要支持更多数量的重载,只需继续添加对应的条件分支即可。
内容的提问来源于stack exchange,提问作者lonewarrior556
相关产品推荐
相关产品推荐

