You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现递归修改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>
    : {};

原理说明

  1. 匹配函数签名:通过条件类型判断T是否为函数类型,提取参数列表P和原返回类型R
  2. 替换返回类型:将当前函数签名的返回类型替换为目标类型U
  3. 递归处理剩余重载:使用Exclude<T, (...args: P) => R>移除已经处理过的签名,递归处理剩余的重载
  4. 终止条件:当没有剩余签名可处理时,返回空对象{},避免多余的类型合并

使用示例

// 生成修改后的类型
type ModifiedChainer<Subject> = RemapFunctionReturnType<Chainer<Subject>, number>;

// 此时 ModifiedChainer 的所有重载返回类型均为 number,符合预期

内容的提问来源于stack exchange,提问作者Michael Stoltz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 12:55:21