我正在尝试在EventEmitter
. 我的目标是创建一个带有 , 的发射器addListener
,removeListener
以及emit
如果我传递一个无效事件或者即使我传递一个与事件签名(args 和 return)不匹配的函数也会在编译器时间中断的方法。
为此,我需要一个 Map 接口(一些带有函数列表的接口),可以在以下类型的 nativeGlobalEventHandlersEventMap
中看到一个示例:
lib.dom.d.ts
//...
interface GlobalEventHandlersEventMap {
"abort": UIEvent;
"animationcancel": AnimationEvent;
"animationend": AnimationEvent;
"animationiteration": AnimationEvent;
//...
到目前为止,我得到了前两种方法:
import { EventEmitter } from "events";
// A simple mapping interface
interface SomeMap {
greeting: (message: string) => void;
}
// This generalization of function is necessary to track
// the list of arguments and result types.
interface GFunc<TArgs extends any[] = any[], TResult = any> {
(...args: TArgs): TResult;
}
// This is a advanced type to mask the EventEmitter class
interface AdvEventEmitter<T extends { [K in keyof T]: GFunc }> {
addListener<K extends keyof T>(event: K, listener: T[K]): void;
removeListener<K extends keyof T>(event: K, listener: T[K]): void;
}
const emitter: AdvEventEmitter<SomeMap> = new EventEmitter();
emitter.addListener('greeting', msg => {
console.log(msg);
});
在上面的代码中,AdvEventEmitter
接口能够对第一个参数强制执行约束:
emitter.addListener('something_else', () => {});
Msg: Argument of type '"something_else"' is not assignable to parameter of type '"greeting"'.
甚至在第二个参数中强制执行参数的类型和数量:
emitter.addListener('greeting', (m1, m2) => {
console.log(m1, m2);
});
Msg: Argument of type '(m1: any, m2: any) => void' is not assignable to parameter of
type '(message: string) => void'.
伟大的。
现在问题出在emit
方法上。
我正在尝试这样的事情:
interface AdvEventEmitter<T extends { [K in keyof T]: GFunc }> {
// ...
emit<K extends keyof T, TArgs extends any[] = any[]>(event: K, ...args: TArgs): void;
}
argevent
已正确验证(如预期的那样),但args
只是任何的通用列表。我不知道如何将TArgs
约束与K
约束联系起来。
有没有办法强制执行此约束?