我正在尝试创建一个通用函数来订阅事件发射器。
subscribe
函数接受 3 个参数:事件名称、事件处理程序和要附加的事件发射器。
如何使其正确推断类型定义,特别是对于事件处理程序,因此当我传递
process
对象作为事件发射器和 'warning'
作为事件名称时,我不必显式声明处理程序参数' 类型:
subscribe('warning', (warning) => {/* */}, process);
// ^
// the `warning` argument should have `Error` type as defined
// in `process` interface:
//
// interface Process {
// ...
// addListener(event: "warning", listener: WarningListener): this;
// }
// ...
//
// type WarningListener = (warning: Error) => void;
这是我的实现以及示例用法。但是,它仅适用于第二个事件(事件
'b'
,不适用于事件 'a'
)。
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: ()=>{},
};
// errors with: Argument of type '"a"' is not assignable to parameter of type '"b"'.
subscribe('a', (a1) => console.log(a1), target);
// works fine
subscribe('b', (b1) => console.log(b1), target);
要推断泛型函数中重载方法的类型,您可以根据发射器和事件名称利用 TypeScript 的条件类型和模板文字类型。使用扩展可能的发射器类型的通用参数定义函数,并使用 TypeScript 的
Parameters
和 ReturnType
实用程序根据传递的事件名称提取和推断事件处理程序的参数和返回类型。不幸的是,如果没有您当前实现的片段,我无法提供定制的代码。然而,专注于条件类型并使用 TypeScript 实用程序提取类型是正确的方法。