TypeScript中实现EventBus的emit方法动态参数类型校验与自动补全
解决TypeScript EventBus的事件自动补全与类型校验问题
你的问题核心在于没有建立事件名与对应回调参数的类型关联,原代码用any和宽泛的string | symbol类型导致TypeScript无法追踪事件的具体参数结构,自然没法提供自动补全和类型校验。
下面是改造后的实现,通过泛型约束事件类型映射,让emit、on、off方法都能基于事件名自动推导参数类型:
// 定义事件映射类型:键是事件名,值是该事件回调的参数元组 type EventMap = Record<string | symbol, any[]>; class EventBus<T extends EventMap = {}> { private listeners: { [K in keyof T]?: ((...args: T[K]) => void)[] } = {}; on<K extends keyof T>(event: K, callback: (...args: T[K]) => void) { if (!this.listeners[event]) { this.listeners[event] = []; } this.listeners[event]!.push(callback); } off<K extends keyof T>(event: K, callback: (...args: T[K]) => void) { const eventListeners = this.listeners[event]; if (!eventListeners) { throw new Error(`Нет события: ${event.toString()}`); } this.listeners[event] = eventListeners.filter(listener => listener !== callback); } emit<K extends keyof T>(event: K, ...args: T[K]) { const eventListeners = this.listeners[event]; if (!eventListeners) { throw new Error(`Нет события: ${event.toString()}`); } eventListeners.forEach(listener => { listener(...args); }); } }
使用示例
当你定义具体的事件类型后,TypeScript会自动提供事件名补全和参数校验:
// 定义你的业务事件映射 type AppEvents = { 'user-login': [username: string, timestamp: number]; 'message-sent': [content: string, recipientId: string]; }; const bus = new EventBus<AppEvents>(); // 自动补全事件名,参数类型严格校验 bus.on('user-login', (username, timestamp) => { console.log(`${username} logged in at ${timestamp}`); }); // 正确调用:参数类型匹配 bus.emit('user-login', 'Alice', Date.now()); // 错误示例:TypeScript会报错,参数数量/类型不匹配 bus.emit('user-login', 'Bob'); // 缺少timestamp参数 bus.emit('message-sent', 123, 'user123'); // content应该是string
关键改造点说明
- 泛型事件映射:通过
T extends EventMap让类接收一个事件类型映射,每个事件名对应其参数元组,TypeScript能据此追踪每个事件的参数结构。 - 索引类型约束:
on/off/emit方法用K extends keyof T约束事件名,确保只能使用预定义的事件名,实现自动补全。 - 参数类型绑定:回调函数和
emit的参数都使用T[K],确保事件名和参数类型严格对应,避免传参错误。
原代码中typeof this.listeners的问题在于,listeners初始是空对象,TypeScript无法推断出未来会添加的事件名,而通过显式的泛型事件映射,我们提前告诉TypeScript所有可能的事件及其参数类型,从而实现预期的类型功能。
内容的提问来源于stack exchange,提问作者Krezo
相关产品推荐
相关产品推荐

