Typescript如何为支持多事件数组的Event API做类型标注?
解决方案
现有基础实现对齐
先对齐你提到的现有基础类型定义,方便后续扩展:
// 业务数据类型 type Apple = { id: string; weight: number }; type Peach = { id: string; sweetness: number }; // 事件类型 type AddAppleEvent = { type: 'addApple'; data: Apple }; type AddPeachEvent = { type: 'addPeach'; data: Peach }; // 事件名-事件类型映射 interface EventMap { addApple: AddAppleEvent; addPeach: AddPeachEvent; }
核心扩展实现
你需要先定义工具类型处理联合转交叉逻辑,再给on方法加函数重载即可:
// 工具类型:联合类型转交叉类型 type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never; class EventApi { // 原有单事件监听签名 on<T extends keyof EventMap>(eventName: T, callback: (evt: EventMap[T]) => void): void; // 新增数组事件监听签名 on<K extends (keyof EventMap)[]>(eventNames: [...K], callback: (evt: Partial<UnionToIntersection<EventMap[K[number]]>>) => void): void; // 运行时实现,原有逻辑不需要修改 on(eventName: string | string[], callback: (evt: any) => void) { // 原有事件绑定逻辑 } }
这里用[...K]可变元组语法是为了让Typescript能正确推导传入的数组字面量的精确类型,而不是放宽为(keyof EventMap)[]通用类型。
效果验证
const api = new EventApi(); // 原有单事件用法,类型推导不受影响 api.on('addApple', evt => { console.log(evt.data.weight); // evt 类型为 AddAppleEvent,属性可直接访问 }); // 新增数组事件用法 api.on(['addApple', 'addPeach'], evt => { // evt 类型为 Partial<AddAppleEvent & AddPeachEvent>,所有属性可选 console.log(evt.type); // 类型为 'addApple' | 'addPeach' | undefined console.log(evt.data?.weight); // 类型为 number | undefined console.log(evt.data?.sweetness); // 类型为 number | undefined });
可选场景:回调参数为事件联合类型
如果你的业务逻辑是触发时只会传入其中一个事件的完整结构(而非合并所有属性的可选结构),可以直接简化签名,不需要联合转交叉:
class EventApi { // 原有单事件签名 on<T extends keyof EventMap>(eventName: T, callback: (evt: EventMap[T]) => void): void; // 简化版多事件签名,回调入参为事件联合类型 on<K extends (keyof EventMap)[]>(eventNames: [...K], callback: (evt: EventMap[K[number]]) => void): void; // 运行时实现同上 } // 使用示例 api.on(['addApple', 'addPeach'], evt => { // evt 类型为 AddAppleEvent | AddPeachEvent if (evt.type === 'addApple') { console.log(evt.data.weight); // 类型收窄后可正常访问专属属性 } else { console.log(evt.data.sweetness); } });
内容的提问来源于stack exchange,提问作者Leo
相关产品推荐
相关产品推荐

