如何为使用arguments的TypeScript方法声明可变参数类型?
兼顾EventEmitter.emit性能与TypeScript类型声明的方案
我有个高频使用的EventEmitter.emit函数,经Babel编译后的基准测试显示,第二个实现版本比第一个快约10%:
// 版本1:性能稍弱 class EventEmitter { emit(eventName: string, ...args: any[]) { const callbacks = this._callbacks[eventName]; if (callbacks) { for (const cb of callbacks) { cb(...args); } } } } // 版本2:性能快10%,但TypeScript无法识别参数类型 class EventEmitter { emit(eventName: string) { const callbacks = this._callbacks[eventName]; if (callbacks) { for (const cb of callbacks) { cb(...Array.prototype.slice.call(arguments, 1)); } } } }
现在需要给版本2的emit方法加上(eventName: string, ...args: any[]) => void的类型声明,但又不能让Babel把未使用的...args编译进最终代码里,以下是几种可行方案:
方案1:类型断言绑定函数类型
先定义目标函数类型,再把实现的函数断言为该类型,让TypeScript认可类型匹配:
type EmitFunction = (eventName: string, ...args: any[]) => void; class EventEmitter { private _callbacks: Record<string, Function[]> = {}; emit: EmitFunction = function(eventName: string) { const callbacks = this._callbacks[eventName]; if (callbacks) { for (const cb of callbacks) { cb(...Array.prototype.slice.call(arguments, 1)); } } }; }
方案2:使用TypeScript函数重载
通过重载签名告知TypeScript方法的参数规范,实际实现则保留高性能版本:
class EventEmitter { private _callbacks: Record<string, Function[]> = {}; // 重载签名:告诉TS这个方法支持任意数量参数 emit(eventName: string, ...args: any[]): void; // 实际实现:无多余参数,保持性能 emit(eventName: string) { const callbacks = this._callbacks[eventName]; if (callbacks) { for (const cb of callbacks) { cb(...Array.prototype.slice.call(arguments, 1)); } } } }
方案3:通过Object.assign扩展类原型
在类定义外部给原型添加方法,同时指定类型,避免类内部的语法限制:
class EventEmitter { private _callbacks: Record<string, Function[]> = {}; } type EmitFunction = (eventName: string, ...args: any[]) => void; Object.assign(EventEmitter.prototype, { emit: function(this: EventEmitter, eventName: string) { const callbacks = this._callbacks[eventName]; if (callbacks) { for (const cb of callbacks) { cb(...Array.prototype.slice.call(arguments, 1)); } } } as EmitFunction });
这些方案的核心逻辑是利用TypeScript类型系统与运行时代码分离的特性:只要让TS认可实现代码符合目标类型,就不需要在运行时保留未使用的...args参数,既满足类型检查需求,又能保留版本2的性能优势。
内容的提问来源于stack exchange,提问作者Leo Jiang
相关产品推荐
相关产品推荐

