1

我正在尝试在EventEmitter. 我的目标是创建一个带有 , 的发射器addListenerremoveListener以及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约束联系起来。

有没有办法强制执行此约束?

4

1 回答 1

1

您需要从中提取K函数的参数T。您可以使用预定义的Parameters条件类型执行此操作:


interface AdvEventEmitter<T extends { [K in keyof T]: GFunc }> {
  emit<K extends keyof T>(event: K, ...args: Parameters<T[K]>): void;
}

游乐场链接

于 2020-07-07T08:27:29.127 回答