【问题标题】:How to type an extensible EventEmitter in TypeScript?如何在 TypeScript 中键入可扩展的 EventEmitter?
【发布时间】:2022-01-25 18:22:09
【问题描述】:

我正在尝试在 TypeScript 中实现可扩展的 EventEmitter 模式。

这是它应该使用的方式:

class DataEmitter<T, _EE extends Dict<any[]>> extends EventEmitter<DefaultMerge<_EE, { data: [T] }>> {
 // ...
}

因此,任何扩展 DataEmitter 的类都可能传递另一个对象类型,定义它能够发出的新事件,依此类推。

这就是我试图定义它的方式:

type Listener<T extends any[]> = (...args: T) => void

type Dict<V> = {
  [name: string]: V
}

type DefaultMerge<A, B> = A & B

type EventEmitter_EE<_EE extends Dict<any[]> = {}> = DefaultMerge<
  _EE,
  {
    listen: [{ event: 'listen' | keyof _EE }]
  }
>

interface EE<_EE extends Dict<any[]> = {}> {
  addListener<K extends keyof _EE>(
    event: K,
    listener: Listener<_EE[K]>
  ): void

  emit<K extends keyof _EE>(event: K, ...args: _EE[K]): void
}

class EventEmitter<_EE extends Dict<any[]> = {}>
  implements EE<EventEmitter_EE<_EE>>
{
  private __listeners: {
    [K in keyof EventEmitter_EE<_EE>]?: Listener<EventEmitter_EE<_EE>[K]>[]
  } = {}

  addListener<K extends keyof EventEmitter_EE<_EE>>(
    event: K,
    listener: Listener<EventEmitter_EE<_EE>[K]>
  ): void {
    this.__listeners[event] = this.__listeners[event] || []
    this.__listeners[event].push(listener)

    // >> TypeScript Error << \\
    this.emit('listen', { event })
  }

  emit<K extends keyof EventEmitter_EE<_EE>>(
    event: K,
    ...args: EventEmitter_EE<_EE>[K]
  ): void {
    const listeners = [...(this.__listeners[event] || [])]

    for (const listener of listeners) {
      listener.call(this, ...args)
    }
  }
}

注意EventEmitter 类带有一个名为"listen" 的默认事件。

但是,TypeScript 抱怨引用的行并显示以下错误消息:

Argument of type '[{ event: K; }]' is not assignable to parameter of type
 '_EE["listen"] & [{ event: "listen" | keyof _EE; }]'.
  Type '[{ event: K; }]' is not assignable to type '_EE["listen"]'.

理想情况下,它应该理解"listen"EventEmitter 的默认事件,并根据定义推断其类型为"listen" | keyof _EE

我的猜测是DefaultMerge&lt;A, B&gt; 定义不明确;它应该返回一个“首先查看 B,然后,如果未定义,则查看 A”的对象类型。

如何摆脱这个错误?

【问题讨论】:

    标签: typescript typescript-generics


    【解决方案1】:
    // >> TypeScript Error << \\
    this.emit('listen', { event })
    

    上述情况的错误是因为 TypeScript 不知道 _EE 在类中是什么,并且考虑到 EventEmitter_EE 已被定义为交集,它试图将类型推断为:

    '_EE["listen"] & [{ event: "listen" | keyof _EE; }]'
    

    在以下情况下,TypeScript 能够推断出_EE

    class SomeClass {
      someMethod() {
        const eventEmitter = new EventEmitter();
        const event = 'listen';
        eventEmitter.addListener(event, () => console.log('eventOccured'));
        eventEmitter.emit('listen', { event });
      }
    }
    
    type click_EE = {
      click: [{event: 'click'}]
    }
    class SomeClass {
      someMethod() {
        const eventEmitter = new EventEmitter<click_EE>();
        const event = 'listen';
        eventEmitter.addListener(event, () => console.log('eventOccured'));
        eventEmitter.emit('listen', { event });
      }
    }
    

    您也可以查看Extensible, strongly typed Event Emitter Interface in Typescript 看看是否有帮助。

    【讨论】:

      猜你喜欢
      • 2017-01-01
      • 1970-01-01
      • 2021-12-14
      • 1970-01-01
      • 2019-09-04
      • 2014-02-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多