-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
/
event-emitter.ts
71 lines (60 loc) · 2.12 KB
/
event-emitter.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
export type GeneralEventTypes = {
// the name of the event and the data it dispatches with
// e.g. 'entryCreated': [count: 1]
[EventName: string]: unknown[] // eslint-disable-line @typescript-eslint/no-explicit-any
}
type EventListener<EventTypes extends GeneralEventTypes, EventName extends keyof EventTypes> = (
...args: EventTypes[EventName]
) => void
type EventMap<EventTypes extends GeneralEventTypes> = {
[EventName in keyof EventTypes]: Set<EventListener<EventTypes, EventName>>
}
/** A simple event emitter that can be used to listen to and emit events. */
class EventEmitter<EventTypes extends GeneralEventTypes> {
private listeners = {} as EventMap<EventTypes>
/** Subscribe to an event. Returns an unsubscribe function. */
public on<EventName extends keyof EventTypes>(
event: EventName,
listener: EventListener<EventTypes, EventName>,
options?: { once?: boolean },
): () => void {
if (!this.listeners[event]) {
this.listeners[event] = new Set()
}
this.listeners[event].add(listener)
if (options?.once) {
const unsubscribeOnce = () => {
this.un(event, unsubscribeOnce)
this.un(event, listener)
}
this.on(event, unsubscribeOnce)
return unsubscribeOnce
}
return () => this.un(event, listener)
}
/** Unsubscribe from an event */
public un<EventName extends keyof EventTypes>(
event: EventName,
listener: EventListener<EventTypes, EventName>,
): void {
this.listeners[event]?.delete(listener)
}
/** Subscribe to an event only once */
public once<EventName extends keyof EventTypes>(
event: EventName,
listener: EventListener<EventTypes, EventName>,
): () => void {
return this.on(event, listener, { once: true })
}
/** Clear all events */
public unAll(): void {
this.listeners = {} as EventMap<EventTypes>
}
/** Emit an event */
protected emit<EventName extends keyof EventTypes>(eventName: EventName, ...args: EventTypes[EventName]): void {
if (this.listeners[eventName]) {
this.listeners[eventName].forEach((listener) => listener(...args))
}
}
}
export default EventEmitter