Универсальный обработчик событий в TypeScript

Я пытаюсь создать общую систему обработчиков событий, которая обеспечивает безопасное использование типов. Не должно быть возможности подписаться на неправильные типы событий (например, this.on('FooEvent', (event : BarEvent) => ...) не разрешено).

Вот что у меня есть:

interface Event {
    type: string;
}
type EventType<T extends Event> = T['type'];
type EventHandler<T extends Event> = (event: T) => void;

class TypedEventHandler<TEvent extends Event> {
    private eventHandlers = new Map<
        EventType<TEvent>,
        EventHandler<TEvent>[]
    >();

    on<TOnEvent extends TEvent, TOnType extends TOnEvent['type']>(
        type: TOnType,
        handler: EventHandler<TOnEvent>,
    ) {
        if (!this.eventHandlers.has(type)) {
            this.eventHandlers.set(type, []);
        }

        this.eventHandlers.get(type)!.push(handler);
    }

    emit(event: TEvent) {
        const handlers = this.eventHandlers.get(event.type);
        if (!handlers) return;

        handlers.forEach(handler => handler(event));
    }
}

К сожалению, .push(handler) не работает с Argument of type 'EventHandler<TOnEvent>' is not assignable to parameter of type 'EventHandler<TEvent>'. Можно ли сделать тип переменной eventHandlers более конкретным, чтобы можно было назначить обработчик?

Я нашел похожие вопросы, подобные этому, однако ни один из них не отвечает на мой вопрос .


person Bjarke Walling    schedule 23.11.2019    source источник
comment
Вот как использовать TypedEventHandler: typescript interface MyEventA extends Event { type: 'MyEventA'; } interface MyEventB extends Event { type: 'MyEventB'; foo3: number; } type MyEvent = MyEventA | MyEventB; export default class SomeClass extends TypedEventHandler<MyEvent> { constructor() { super(); this.addEventHandler('MyEventB', this.handler.bind(this)); } handler(event: MyEventB) { // MyEventA is error // ... } doSomething() { this.emit({ type: 'MyEventB', foo3: 42 }); } }   -  person Bjarke Walling    schedule 23.11.2019