You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 23:22:51