用 T[K] 定义 Map

define Map with T[K]

我目前正在从 JS 过渡到 TS,无法完全理解 keyof。我找到了 https://github.com/kimamula/TypeScript-definition-of-EventEmitter-with-keyof,现在我正在尝试实现它。一切顺利,直到我打开 'noImplicitAny'.

我在 ts 操场上做了一个 example 来说明我遇到的问题:

在构造函数中无法访问 K 所以我必须显式地创建 Map (arg: any) 才能让它工作。

创建地图时是否有避免使用 any 的解决方案?

问题是您正试图将 (arg: keyof T) => any 分配给 (arg: T[K]) => anykeyof T 表示 T 的任何 属性 名称 例如在这个 class:

class X { test: string; test2: number; }

keyof X 等同于 'test' | 'test2'T[K]K extends keyof T 表示 T 的 属性 的类型,名称为 K,所以对于上面的 class T[K] 可以是 numberstring,具体取决于为 K

传递的值

因此,如果您有 Emitter<X>,您基本上会尝试将 (arg: string | number) => any 分配给 (arg: 'test' | 'test2') => any,这绝对不是类型安全的。

我的猜测是,您想限制 listener 具有与 class 成员相同的 属性 类型的参数。为此,您应该使用 Map<string, ((arg: T[keyof T]) => any) []>arg 限制为任何可能的 属性 类型的 T

class EventEmitter<T> {

  private events: Map<string, ((arg: T[keyof T]) => any) []>;

  constructor() {
    this.events = new Map<string, ((arg: T[keyof T]) => any) []>();
  }

  public getOrCreateEvents<K extends keyof T>(event: K, listener: (arg: T[K]) => any): ((arg: T[K]) => any) [] {

    return this.events.get(event) || this.events.set(event, new Array<(arg: T[K]) => any>()).get(event);
  }
}

// Test 
class X { test: string; test2: number; }
var d = new EventEmitter<X>();
d.getOrCreateEvents("test2", c => console.log(c));// c is infered to string
d.getOrCreateEvents("test2", c => console.log(c)); // c is infered to number