如何在泛型事件订阅函数中推断重载方法的类型?
泛型事件订阅函数的类型推断问题解决
我需要实现一个泛型subscribe函数,参数包括事件名称、事件处理函数和目标事件发射器,核心要求是自动推断处理函数的参数类型——比如传入Node.js的process对象和'warning'事件名时,处理函数的参数能自动识别为Error类型,不用手动声明。
原实现存在类型推断问题:下面的代码里,调用subscribe处理'b'事件正常,但处理'a'事件时会报错Argument of type '"a"' is not assignable to parameter of type '"b"':
interface Target<N, H> { on(name: N, handler: H): unknown; } const subscribe = < N extends T extends Target<infer N, unknown> ? N : never, H extends T extends Target<N, infer H> ? H : never, T extends Target<unknown, unknown>, >( name: N, handler: H, target: T ) => { target.on(name, handler); }; const target: { on(name: 'a', handler: (a1: string) => void): void; on(name: 'b', handler: (b1: number) => void): void; } = { on: ()=>{}, }; // 报错:类型"a"无法赋值给类型"b" subscribe('a', (a1) => console.log(a1), target); // 正常工作 subscribe('b', (b1) => console.log(b1), target);
问题原因
原Target接口假设事件发射器的on方法只支持单一事件和单一处理函数类型,但实际很多事件发射器(包括示例中的target)的on方法是重载的,能处理多种事件-处理函数组合。原泛型的约束逻辑无法正确解析重载方法的类型关联,导致TypeScript只能推断出最后一个重载的类型(也就是'b'事件对应的类型)。
正确实现
调整泛型定义顺序,配合条件类型提取重载方法中事件名对应的处理函数类型:
// 工具类型:从事件发射器T中,提取事件E对应的处理函数类型 type EventHandler<T, E extends string> = T extends { on(event: E, handler: infer H): any } ? H : never; const subscribe = <T, E extends string>( eventName: E, handler: EventHandler<T, E>, target: T ) => { target.on(eventName, handler); };
验证效果
用之前的target测试,两个事件都能正确推断类型:
const target: { on(name: 'a', handler: (a1: string) => void): void; on(name: 'b', handler: (b1: number) => void): void; } = { on: () => {}, }; // a1自动推断为string类型,无报错 subscribe('a', (a1) => console.log(a1), target); // b1自动推断为number类型,正常工作 subscribe('b', (b1) => console.log(b1), target); // 测试process的warning事件,warning自动推断为Error类型 subscribe('warning', (warning) => { console.log(warning.message); }, process);
原理说明
- 先让TypeScript推断出事件发射器
T的完整类型(包括所有重载的on方法); - 再根据传入的
eventName推断出具体的事件类型E; - 最后通过
EventHandler工具类型,从T的重载on方法中提取对应E的处理函数类型,实现自动关联。
内容的提问来源于stack exchange,提问作者Maksim Kalinin
相关产品推荐
相关产品推荐

