如何在TypeScript中为TinyEmitter实现带类型提示的事件总线方法
实现带类型提示的TinyEmitter事件方法
要让addEventListener和emit具备事件名称与参数的类型提示,核心是将你定义的EventMap函数数组转换为事件名-参数数组的映射类型,再基于这个映射为方法做泛型约束。以下是具体实现步骤:
1. 定义类型转换工具
首先需要把EventMap中的每个事件处理函数,提取出事件名和对应的参数数组:
// 从单个事件处理函数中提取事件名与参数 type ExtractEvent<T> = T extends (e: infer EventName, ...args: infer Args) => void ? { event: EventName; args: Args } : never; // 将EventMap数组转换为事件信息的联合类型 type EventUnion = ExtractEvent<EventMap[number]>; // 最终得到事件名到参数数组的映射 type EventRecord = { [E in EventUnion['event']]: Extract<EventUnion, { event: E }>['args'] };
以你提供的EventMap为例,EventRecord会被推断为:
type EventRecord = { event1: [number, string, string]; event2: [string, string]; };
2. 为TinyEmitter实现类型化方法
基于EventRecord,给addEventListener和emit添加泛型约束,让TypeScript根据事件名自动推断参数类型:
interface TinyEmitter { // 监听事件:事件名对应参数类型严格匹配 addEventListener<E extends keyof EventRecord>( event: E, handler: (...args: EventRecord[E]) => void ): void; // 触发事件:参数类型与对应事件绑定 emit<E extends keyof EventRecord>( event: E, ...args: EventRecord[E] ): void; }
3. 使用示例
此时调用方法会自动获得类型提示:
const emitter: TinyEmitter = /* 你的TinyEmitter实例 */; // 正确:arg1推断为number,arg2/arg3为string emitter.addEventListener('event1', (arg1, arg2, arg3) => { console.log(arg1.toFixed()); // 类型安全,arg1是number }); // 错误:参数数量/类型不匹配会报错 emitter.emit('event1', 'wrong-type', 123); // 正确:参数与event2的类型完全匹配 emitter.emit('event2', 'hello', 'world');
说明
- 这种方式不需要修改你原有的
EventMap定义,仅通过类型转换实现类型推导 - 后续新增事件只需在
EventMap中添加对应的函数,EventRecord会自动更新,无需手动维护映射关系
内容的提问来源于stack exchange,提问作者Kasi
相关产品推荐
相关产品推荐

