T类型的与打字稿相关的键不能互相分配

时间:2019-04-08 11:33:37

标签: typescript generics

我有一个简单的事件分派器类,该类使用类似于DOM类型定义上的addEventListener的方法以及将事件名称映射到事件类的事件映射。

interface EventMap {
  [type: string]: any // tslint:disable-line no-any
}

type Listener<T, K extends keyof T> = (event: T[K]) => void

export class Dispatcher<T extends EventMap, K extends keyof T = keyof T> {
  /**
   * The current list of listeners.
   */
  private listeners: { [key: string]: Listener<T, K>[] } = {}

  /**
   * Add a new event listener.
   *
   * @param type The type of event to list to.
   * @param listener The function that should be called when the event is dispatched.
   */
  addEventListener<EventType extends K> (type: EventType, listener: Listener<T, EventType>): void {
    // Workaround: Type 'EventType' cannot be used to index type '{ [key: string]: Listener<T, K>[]; }'
    const key: string = type as string
    if (! (key in this.listeners)) {
      this.listeners[key] = []
    }

    this.listeners[key].push(listener)
  }

  /**
   * Remove an event listener.
   *
   * @param type The type of event to remove a listener for. If no listener is
   * given, all event listeners for this type will be removed.
   * @param listener The listener to remove.
   */
  removeEventListener<EventType extends K> (type: EventType, listener?: Listener<T, EventType>): void {
    const key: string = type as string
    if (! (key in this.listeners)) {
      return
    }

    if (listener) {
      const index = this.listeners[key].indexOf(listener)
      if (index === -1) {
        return
      }

      this.listeners[key].splice(index, 1)
    } else {
      delete this.listeners[key]
    }
  }

  /**
   * Dispatch an event.
   *
   * @param type The type of event to dispatch.
   * @param event The event payload.
   */
  dispatch<EventType extends K> (type: EventType, event: T[EventType]): void {
    const key: string = type as string
    if (! (key in this.listeners)) {
      return
    }

    this.listeners[key].forEach(listener => listener(event))
  }
}

将使用类似这样的内容:

class ChangeEvent {
  constructor (public readonly value: string) {
  }
}

interface EventMap {
  'change': ChangeEvent
}

const dispatcher = new Dispatcher<EventMap>()

这很好,但是自从Typescript 3.4(从3.3版)更新以来,我在添加和查找侦听器数组,pushindexOf调用的事件侦听器的行上遇到类型错误

Argument of type 'Listener<T, EventType>' is not assignable to parameter of type 'Listener<T, K>'.
  Type 'K' is not assignable to type 'EventType'.
    Type 'keyof T' is not assignable to type 'EventType'.
      Type 'string | number | symbol' is not assignable to type 'EventType'.
        Type 'string' is not assignable to type 'EventType'.

我可能做错了什么,但看不到。 EventType扩展了K,为什么这不起作用?对于我来说,“类型'string'不能分配给类型'EventType'”尤其没有意义,因为keyof T肯定会包含string

0 个答案:

没有答案