给订阅发布函数添加类型推导

想着挺简单,打算自己随意实现个。发现没有类型推导有些别扭,于是搜了搜资料结合自己使用习惯改进了一下,试试吧~ (折腾了挺久,早知道直接找个 Library 用了。。。)

type AnyFunction = (...args: any[]) => any;

export class Emitter<T extends Record<keyof T, AnyFunction>> {
  store: { [K in keyof T]?: Array<T[K]> } = {};
  on<K extends keyof T>(event: K, callback: T[K]) {
    this.store[event] = (this.store[event] || []).concat(callback);
  }
  off<K extends keyof T>(event: K, callback: T[K]) {
    this.store[event] = (this.store[event] || []).filter(
      (cb) => cb !== callback
    );
  }
  emit<K extends keyof T>(event: K, ...args: Parameters<T[K]>) {
    const callbacks = this.store[event];
    callbacks?.forEach((cb) => {
      cb.call(undefined, ...args);
    });
  }
}

interface EventMap {
  drag: (id: number) => void;
}

export const emitter = new Emitter<EventMap>();

// OK!
emitter.emit('drag', 63307);

// Argument of type 'string' is not assignable to parameter of type 'number'.
emitter.emit('drag', '63307');

// Argument of type '(id: string) => void' is not assignable to parameter of type '(id: number) => void'.
emitter.on('drag', (id: string) => {
  console.log(id);
});