【问题标题】:How to make a strongly typed event emitters in my TypeScript class?如何在我的 TypeScript 类中创建强类型事件发射器?
【发布时间】:2021-02-11 13:13:56
【问题描述】:

我正在尝试在我的 TypeScript 类中创建一个强类型事件发射器,但我遇到了一些麻烦。 我在以下代码中有 2 个错误:

type AudioEvents = {
    "start": (title: string) => void,
    "stop": () => void
}

export class Audio {
    private _listeners: {
        [E in keyof AudioEvents]: Array<AudioEvents[E]>
    } = {
        "start": [],
        "stop": []
    };

    on<E extends keyof AudioEvents>(event: E, listener: AudioEvents[E]) {
        this._listeners[event].push(listener);
    }

    private emit<E extends keyof AudioEvents>(event: E, ...args: Parameters<AudioEvents[E]>) {
        this._listeners[event].forEach(listener => {
            listener(args);
        });
    }
}

这是第一个错误:

Argument of type 'AudioEvents[E]' is not assignable to parameter of type '() => void'.
  Type '((title: string) => void) | (() => void)' is not assignable to type '() => void'.
    Type '(title: string) => void' is not assignable to type '() => void'.

            this._listeners[event].push(listener);

这是第二个:

Argument of type 'Parameters<AudioEvents[E]>' is not assignable to parameter of type 'string'.
  Type 'unknown[]' is not assignable to type 'string'.
    Type '[] | [title: string]' is not assignable to type 'string'.
      Type '[]' is not assignable to type 'string'.

                listener(args)

我不明白为什么会出现这些错误,但我认为这是做事件发射器的好方法,因为我的 IDE 喜欢它:

我想实际上这两个错误是由于同一个误解造成的。 您有解决这些错误的想法吗?

【问题讨论】:

    标签: typescript eventemitter


    【解决方案1】:

    不幸的是,Typescript 没有依赖类型。 见Suggestion for Dependent-Type-Like Functions: Conservative Narrowing of Generic Indexed Access Result Type #33014

    所描述的问题是您的问题的一对一映射。

    在你的情况下,我会为每个事件使用不同的函数:

    type StartCallback = (title: string) => void;
    type StopCallback = () => void;
    
    export class Audio {
        private _startListeners: StartCallback[] = [];
        private _stopListeners: StopCallback[] = [];
        
    
        public onStart(listener: StartCallback) {
            this._startListeners.push(listener);
        }
    
        public onStop(listener: StopCallback) {
            this._stopListeners.push(listener);
        }
    
        private emitStart(title: string) {
            this._startListeners.forEach(listener => {
                listener(title);
            });
        }
    
        private emitStop() {
            this._stopListeners.forEach(listener => {
                listener();
            });
        }
    }
    

    【讨论】:

    • 也许像这样? type AudioEvents = { start: [string], stop: [] }; 用于类型声明,private _listeners: {[E in keyof AudioEvents]: Array&lt;(...arg: AudioEvents[E]) =&gt; void&gt;} 用于侦听器列表属性,on&lt;E extends keyof AudioEvents&gt;(event: E, listener: (...arg: AudioEvents[E]) =&gt; void): void 用于on() 定义,private emit&lt;E extends keyof AudioEvents&gt;(event: E, ...args: AudioEvents[E]): void 用于emit() 定义?我在listener(args) 行的emit() 中还有一个错误,但我认为它更好,你不觉得吗?
    • 错误是Argument of type 'AudioEvents[E]' is not assignable to parameter of type 'string'. Type '[string] | []' is not assignable to type 'string'. Type '[string]' is not assignable to type 'string'.
    • 代码中的2个问题:1.联合没有被事件的类型缩小范围:Type '[string] | []' is not assignable to type 'string'. 2.你没有像 listener(...args); 那样解构记录;并获取Type '[string]' is not assignable to type 'string'.
    猜你喜欢
    • 2019-09-09
    • 2014-06-03
    • 1970-01-01
    • 2018-03-19
    • 2021-05-21
    • 2018-01-02
    • 1970-01-01
    • 2012-09-23
    相关资源
    最近更新 更多