Created
April 2, 2023 21:47
-
-
Save HKhademian/2ead6bf59b0ff43b418d22c41576be36 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bun | |
import { EventButs } from "./EventBu"; | |
enum MyEvents1 { | |
Val1 = 'Val1', | |
Event1 = 'Event1', | |
Event2 = 'Event2', | |
Event3 = 'Event3', | |
}; | |
interface MyEvents1Def { | |
[MyEvents1.Val1]: number; | |
[MyEvents1.Event1](arg1: string, arg2: number): void; | |
[MyEvents1.Event2](arg1: number, arg2: string): void; | |
[MyEvents1.Event3](arg1: HTMLElement): void; | |
}; | |
const bus = EventButs.get<MyEvents1Def>(); | |
bus.on(MyEvents1.Event1, (arg1, arg2) => { | |
console.log(arg1, arg2); | |
}); | |
// pass | |
bus.emit(MyEvents1.Event1, 'hello', 1); | |
// error: string is not assignable to number | |
bus.emit(MyEvents1.Event2, 1 + "", 'hello'); | |
// error: null is not assignable to HTMLElement | |
bus.emit(MyEvents1.Event3, null); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const CHANNELS: { [key: string]: EventButs<unknown> } = {}; | |
/** | |
* EventBuTS is a simple event emitter that can be used to emit events to multiple listeners | |
*/ | |
export class EventButs<EventDef> { | |
private eventListeners: { [key in keyof Methods<EventDef>]?: (Methods<EventDef>[key])[] } = {}; | |
private constructor() { } | |
static get<EventDef = unknown>(channelName?: string): EventButs<EventDef> { | |
channelName = channelName && channelName.length > 0 ? channelName.toLocaleLowerCase() : ''; | |
return (CHANNELS[channelName] as EventButs<EventDef>) | |
|| (CHANNELS[channelName] = new this<EventDef>()); | |
}; | |
/** | |
* add a listener | |
* @param eventName name the event to add the listener to | |
* @param callback the callback to add | |
*/ | |
public on<EventName extends keyof Methods<EventDef>>( | |
eventName: EventName, | |
callback: Methods<EventDef>[EventName], | |
) { | |
const eventListeners: Methods<EventDef>[EventName][] = this.eventListeners[eventName] || (this.eventListeners[eventName] = []); | |
eventListeners.push(callback); | |
return () => this.off(eventName, callback); | |
} | |
/** | |
* remove a listener | |
* @param eventName name the event to remove the listener from | |
* @param callback the callback to remove | |
*/ | |
public off<EventName extends keyof Methods<EventDef>>( | |
eventName: EventName, | |
callback: Methods<EventDef>[EventName], | |
): void { | |
const eventListeners = this.eventListeners[eventName] || []; | |
let index; | |
while ((index = eventListeners.indexOf(callback)) >= 0) { | |
eventListeners.splice(index, 1); | |
} | |
} | |
/** | |
* emit an event, it will execute in the next tick | |
* FIFO is garanteed, both for the listeners and events | |
* @param eventName name the event to emit to all listeners | |
* @param args arguments to pass to the listeners | |
*/ | |
public emit<EventName extends keyof Methods<EventDef>>( | |
eventName: EventName, | |
...args: Params<EventDef, EventName> | |
): void { | |
setTimeout(() => { | |
this.emitNow(eventName, ...args); | |
}, 0); | |
} | |
/** | |
* immidiately emit an event and catch all errors | |
* @param eventName name the event to emit to all listeners | |
* @param args arguments to pass to the listeners | |
*/ | |
public emitNow<EventName extends keyof Methods<EventDef>>( | |
eventName: EventName, | |
...args: Params<EventDef, EventName> | |
): void { | |
const eventListeners: Methods<EventDef>[EventName][] = this.eventListeners[eventName] || []; | |
for (const callback of eventListeners) { | |
try { | |
callback(...args); | |
} | |
catch (e) { | |
console.error(e); | |
} | |
} | |
} | |
} | |
/** | |
* Get all method keys of a type | |
*/ | |
type _MethodKeys<T> = ({ [P in keyof T]: T[P] extends ((...args: any[]) => any) ? P : never })[keyof T]; | |
type Methods<T> = { [P in _MethodKeys<T>]: T[P] extends ((...args: any[]) => any) ? T[P] : never }; | |
type Params<T, K extends keyof Methods<T>> = Parameters<Methods<T>[K]>; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment