TypeScript: специализированные подписи для событий подкласса EventEmitter

У меня есть базовый класс EventEmitter, в котором есть метод on для привязки обработчиков к определенным событиям:

class EventEmitter {
    on(event: string, handler: Function) {
        /* add handler internally */
    }

    protected emit(event: string, ...args) {
        /* call all handlers listening on event */
    }
}

Теперь у меня есть разные подклассы, которые могут генерировать разные события с разными аргументами. Я хотел бы «объявить», какие события могут быть созданы этим конкретным классом:

class MyClass extends EventEmitter {
    on(event: 'event1', handler: (arg1: number) => void): void;
    on(event: 'event2', handler: (arg1: string, arg2: number) => void): void;
}

Таким образом, мой подкласс может генерировать события event1 и event2, но это не кажется правильным способом указания. TypeScript (tsc 1.8) сочетается:

error TS2415: Class 'MyClass' incorrectly extends base class 'EventEmitter'.
  Types of property 'on' are incompatible.
Type '(event: "event1", handler: (arg1: number) => void) => void' is not assignable to type '(event: string, handler: Function) => void'.
  Type '(event: "event1", handler: (arg1: number) => void) => void' provides no match for the signature '(event: string, handler: Function): void'
error TS2382: Specialized overload signature is not assignable to any non-specialized signature.
error TS2391: Function implementation is missing or not immediately following the declaration.

Итак, каков предполагаемый способ указать события, которые мой класс может генерировать?

РЕДАКТИРОВАТЬ: я нашел имя того, что искал: Специальные подписи. Однако похоже, что он предназначен только для интерфейсов, а не для нового кода TypeScript.

Теперь я нашел еще один вопрос о том же выпуск от 2015 года, однако решение там выглядит не совсем правильным. Итак, есть ли сегодня другие способы сделать это в TypeScript?


person Simon    schedule 01.03.2016    source источник
comment
Этот ответ должен вам помочь.   -  person aleclarson    schedule 15.09.2018


Ответы (1)


каков предполагаемый способ указать события, которые мой класс может генерировать?

Вместо использования одного потока event, содержащего все типы, проще иметь отдельный поток event для каждого тип.

Эту концепцию я называю TypedEvent. Один пример проекта, в котором он используется, — http://alm.tools/.

Реализация: https://github.com/alm-tools/alm/blob/55a8eb0f8ee411a506572abce92085235658b980/src/common/events.ts#L20-L72

Вот пример использования: https://github.com/alm-tools/alm/blob/55a8eb0f8ee411a506572abce92085235658b980/src/server/lang/errorsCache.ts#L10

export let errorsUpdated = new TypedEvent<ErrorsUpdate>();
// emit: 
errorsUpdated.emit({} /* this will be type checked */);
// consume:
errorsUpdated.on((x)=>null); // x has the correct inferred type
person basarat    schedule 01.03.2016
comment
Это может быть подход, однако, похоже, это другой стиль. Я хотел бы адаптировать существующий стиль node.js (instance.on(eventName, handler)) и HTML DOM (element.addEventListener(eventName, handler)). - person Simon; 02.03.2016
comment
Стандартный стиль node.js не создавался с учетом статической проверки типов. Он опирается на документацию, а не на анализ времени кода, и не так хорошо моделируется в машинописном тексте. - person basarat; 02.03.2016
comment
Не могли бы вы показать мне пример вашего подхода, используя мои примеры классов и событий? Если я правильно понимаю, я должен определить подкласс события для каждого возможного события. Мои модули не являются внешними, и мои классы используют одно и то же пространство имен. Два класса могут генерировать 'event1' / Event1Event, но иметь разные свойства, в зависимости от класса, генерирующего его. - person Simon; 02.03.2016