Búsqueda de sitios web

Tipos de Tipado de EventEmitter en Typescript


Estoy implementando event emitter pero me encontré con un problema con los tipos en TypeScript. Por favor, dime cómo hacer que esto funcione.

export type IEventMap = {
    "mount": () => void;
    "mounted": () => void;
    "unmount": () => void;
    "unmounted": () => void;
    "test1": (stringArg: string) => void;
    "test2": (numberArg: number) => void;
};

export type IEventNames = keyof IEventMap;
export type IEventFn<K extends IEventNames> = IEventMap[K];
export type IEventListeners = { [K in IEventNames]?: Set<IEventFn<K>> };

export default class Events {

    private readonly listeners: IEventListeners = {};

    public on <K extends IEventNames> (eventName: K, callback: IEventFn<K>) {

        if (!this.listeners[eventName]) {
            this.listeners[eventName] = new Set();
        }

        this.listeners[eventName].add(callback);

    }

    public off <K extends IEventNames> (eventName: K, callback: IEventFn<K>) {

        if (this.listeners[eventName]) {
            this.listeners[eventName].delete(callback);
        }

    }

    public emit <K extends IEventNames> (eventName: K, ...args: Parameters<IEventFn<K>>) {

        if (this.listeners[eventName]) {
            this.listeners[eventName].forEach(callback => callback(...args));
        }

    }

}

// test

const events = new Events();

events.on("mount", () => {
    console.log("mount");
});

events.on("test1", arg => {
    console.log(arg);
});

events.on("test2", arg => {
    console.log(arg);
});

events.emit("mount");
events.emit("test1", "test string");
events.emit("test2", 1);

Errores

El tipo 'Set' no se puede asignar al tipo 'IEventListeners[K]'. El tipo 'Set' no se puede asignar al tipo 'Set<() => void> & Set<() => void> & Set<() => void> & Set<() => void> & Set<(stringArg: string) => void> & Set<(numberArg: number) => void>'. El tipo 'Set' no se puede asignar al tipo 'Set<() => void>'. El tipo 'IEventFn' no se puede asignar al tipo '() => void'. El tipo '(() => void) | (() => void) | (() => void) | (() => void) | ((stringArg: string) => void) | ((numberArg: number) => void)' no se puede asignar al tipo '() => void'. El tipo '(stringArg: string) => void' no se puede asignar al tipo '() => void'.

El objeto posiblemente es 'undefined'. El objeto posiblemente es 'undefined'. El objeto posiblemente es 'undefined'.

Un argumento spread debe tener un tipo de tupla o pasarse a un parámetro rest.

Enlace del parque

Respuesta #1

  1. Las callbacks intercambiables deberían ser en realidad REST-ARGS, así que
export type IEventFn<K extends IEventNames> = (...a: Parameters<IEventMap[K]>) => void;

soluciona la mitad de los errores

  1. ts no recuerda el tipo si si por cualquier razón, simplemente usa ?.
this.listeners[eventName]?.delete(callback);
  1. ts no quiere asignar tipos que no coinciden, reduce el tipo para que los tipos coincidan
let l: { [KK in K]?: Set<IEventFn<KK>> } = this.listeners;
(l[eventName] ??= new Set<IEventFn<K>>()).add(callback);

parque infantil

Artículos relacionados