Create a mixin that adds `on`, `off`, and `emit` to any base class. Type the internal map and ensure `this` is the instance using a generic constructor signature.
Example code
type Ctor<T = {}> = new (...a: any[]) => T;
function WithEvents<TBase extends Ctor>(Base: TBase){
return class extends Base {
private _events = new Map<string, Set<Function>>();
on(event: string, handler: Function){
const set = this._events.get(event) ?? new Set();
set.add(handler); this._events.set(event, set);
}
off(event: string, handler: Function){ this._events.get(event)?.delete(handler); }
emit(event: string, ...args: any[]){ this._events.get(event)?.forEach(h => h(...args)); }
};
}
class Model {}
class EventedModel extends WithEvents(Model) {}
const m = new EventedModel();
m.on('save', (x: any) => console.log('saved', x));
m.emit('save', { id: 1 });