受限场景下TypeScript对象实现独立类型化事件发射器的最优方案
实现带类型负载的实例级事件发射器方案
一、自行实现轻量泛型事件类
自己写一个极简的泛型事件类是最灵活的选择,完全满足你的所有限制,而且代码量极小:
// 泛型事件发射器,支持指定负载类型 class TypedEvent<T> { private callbacks: Array<(payload: T) => void> = []; // 添加回调,返回移除函数方便取消监听 addCallback(callback: (payload: T) => void) { this.callbacks.push(callback); return () => { this.callbacks = this.callbacks.filter(cb => cb !== callback); }; } // 触发事件,传递负载 emit(payload: T) { // 复制回调数组,避免触发时移除回调导致遍历异常 [...this.callbacks].forEach(callback => callback(payload)); } // 可选:清空所有回调 removeAllCallbacks() { this.callbacks = []; } } // 你的基础类 class BaseClass { public someProperty: number = 0; } // 业务类,把TypedEvent作为成员变量使用(组合而非继承) class ProcessDoer extends BaseClass { public onProcessDone: TypedEvent<number>; constructor() { super(); this.onProcessDone = new TypedEvent<number>(); setInterval(() => { this.someProperty = Math.random(); this.onProcessDone.emit(this.someProperty); }, 1000); } } // 使用示例 const processDoer1 = new ProcessDoer(); const processDoer2 = new ProcessDoer(); // 只监听processDoer2的事件 const unsubscribe = processDoer2.onProcessDone.addCallback((result) => { console.log("第二个ProcessDoer完成任务,结果:", result); }); // 要取消监听的话直接调用unsubscribe() // unsubscribe();
这个实现完美匹配你的需求:
- 无需继承:通过组合方式把事件类作为成员变量,完全不影响原有类的继承关系
- 封装性:只有持有ProcessDoer实例引用的代码才能访问onProcessDone,没有全局注册入口
- 实例级监听:每个ProcessDoer实例的onProcessDone都是独立的,监听只会针对特定实例生效
二、现成npm包方案
如果不想自己造轮子,这些轻量的事件库可以直接用,同样通过组合方式集成:
1. tiny-emitter(超轻量)
tiny-emitter体积极小,API简洁,配合类型声明支持TypeScript:
安装命令:
npm install tiny-emitter npm install -D @types/tiny-emitter
使用示例:
import Emitter from 'tiny-emitter'; class ProcessDoer extends BaseClass { // 泛型指定事件与负载类型的映射 public onProcessDone: Emitter<{ 'done': [number] // 事件名对应回调参数的类型数组 }>; constructor() { super(); this.onProcessDone = new Emitter(); setInterval(() => { this.someProperty = Math.random(); this.onProcessDone.emit('done', this.someProperty); }, 1000); } } // 监听特定实例的事件 processDoer2.onProcessDone.on('done', (result) => { console.log("第二个ProcessDoer完成任务,结果:", result); });
2. mitt(天生支持TS泛型)
mitt是另一个极简库,原生支持TypeScript泛型,类型定义更直观:
安装命令:
npm install mitt
使用示例:
import mitt from 'mitt'; // 定义事件类型映射 type ProcessEvents = { processDone: number; }; class ProcessDoer extends BaseClass { public onProcessDone: mitt.Emitter<ProcessEvents>; constructor() { super(); this.onProcessDone = mitt<ProcessEvents>(); setInterval(() => { this.someProperty = Math.random(); this.onProcessDone.emit('processDone', this.someProperty); }, 1000); } } // 监听特定实例的事件 processDoer2.onProcessDone.on('processDone', (result) => { console.log("第二个ProcessDoer完成任务,结果:", result); });
这些包的优势:
- 无需继承,都是实例化后作为成员变量使用
- 完全是实例级事件,没有全局污染
- 自带TypeScript类型支持,满足带类型负载的需求
内容的提问来源于stack exchange,提问作者goose_lake
相关产品推荐
相关产品推荐

