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

如何在TypeScript代理函数中推断函数参数类型

动态调用类方法时的参数类型错误问题

问题描述

尝试实现一个“proxy”方法用于动态调用类的其他方法,处理参数类型时遇到以下错误提示:
A spread argument must either have a tuple type or be passed to a rest parameter.

按照文档说明,Parameters工具函数应返回元组类型,但为何会出现这个错误?

相关代码示例:

class testClass {
  public methodA(a: number): void {
  }

  public methodB(b: string): void {
  }

  public callRandom(methodName: 'methodA', options: [number]): void;
  public callRandom(methodName: 'methodB', options: [string]): void;
  public callRandom(methodName: 'methodA' | 'methodB', options: [number] | [string]) {
      type optionsType = Parameters<this[typeof methodName]>; 
      this[methodName](...options as optionsType);
  }
}

问题根源

核心问题在于联合类型的类型收窄失效:

  • this[typeof methodName]是typeof methodA | typeof methodB的联合类型,对应的Parameters返回结果是[number] | [string]——这是两个元组的联合,而非单个确定的元组类型。
  • TypeScript无法在编译期确认methodName和options的具体类型是否严格匹配,因此会判定...options的类型不明确,不符合展开参数的要求。

解决方案

方案一:使用泛型关联类型(推荐)

通过泛型让TypeScript明确methodName和参数类型的对应关系,代码更简洁且扩展性强:

class testClass {
  public methodA(a: number): void {
  }

  public methodB(b: string): void {
  }

  public callRandom<T extends keyof this>(
    methodName: T, 
    ...options: Parameters<this[T]>
  ): void {
    this[methodName](...options);
  }
}

方案二:分支判断收窄类型(兼容原有重载结构)

如果需要保留原有的重载定义,可通过运行时分支判断来收窄类型,让TypeScript确认参数匹配:

class testClass {
  public methodA(a: number): void {
  }

  public methodB(b: string): void {
  }

  public callRandom(methodName: 'methodA', options: [number]): void;
  public callRandom(methodName: 'methodB', options: [string]): void;
  public callRandom(methodName: 'methodA' | 'methodB', options: [number] | [string]) {
    if (methodName === 'methodA') {
      this[methodName](...options as [number]);
    } else {
      this[methodName](...options as [string]);
    }
  }
}

内容的提问来源于stack exchange,提问作者Marian Bazalik

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 18:54:59