如何在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
相关产品推荐
相关产品推荐

