-
Notifications
You must be signed in to change notification settings - Fork 141
/
index.ts
65 lines (60 loc) · 1.7 KB
/
index.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
type EventName = string
type EventFnArgs = any[]
type EmitterContract = Record<EventName, EventFnArgs>
/**
* Event Emitter that takes the expected contract as a generic
* @example
* ```ts
* type Contract = {
* delivery_success: [DeliverySuccessResponse, Metrics],
* delivery_failure: [DeliveryError]
* }
* new Emitter<Contract>()
* .on('delivery_success', (res, metrics) => ...)
* .on('delivery_failure', (err) => ...)
* ```
*/
export class Emitter<Contract extends EmitterContract = EmitterContract> {
private callbacks: Partial<Contract> = {}
on<EventName extends keyof Contract>(
event: EventName,
callback: (...args: Contract[EventName]) => void
): this {
if (!this.callbacks[event]) {
this.callbacks[event] = [callback] as Contract[EventName]
} else {
this.callbacks[event]!.push(callback)
}
return this
}
once<EventName extends keyof Contract>(
event: EventName,
callback: (...args: Contract[EventName]) => void
): this {
const on = (...args: Contract[EventName]): void => {
this.off(event, on)
callback.apply(this, args)
}
this.on(event, on)
return this
}
off<EventName extends keyof Contract>(
event: EventName,
callback: (...args: Contract[EventName]) => void
): this {
const fns = this.callbacks[event] ?? []
const without = fns.filter((fn) => fn !== callback) as Contract[EventName]
this.callbacks[event] = without
return this
}
emit<EventName extends keyof Contract>(
event: EventName,
...args: Contract[EventName]
): this {
const callbacks = this.callbacks[event] ?? []
callbacks.forEach((callback) => {
callback.apply(this, args)
})
return this
}
}