This repository was archived by the owner on Jun 26, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 27
/
Copy pathevents.ts
97 lines (75 loc) · 2.85 KB
/
events.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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
export interface EventCallback<EventType> { (evt: EventType): void }
export interface EventObject<EventType> { handleEvent: EventCallback<EventType> }
export type EventHandler<EventType> = EventCallback<EventType> | EventObject<EventType>
interface Listener {
once: boolean
callback: any
}
/**
* Adds types to the EventTarget class. Hopefully this won't be necessary forever.
*
* https://github.com/microsoft/TypeScript/issues/28357
* https://github.com/microsoft/TypeScript/issues/43477
* https://github.com/microsoft/TypeScript/issues/299
* etc
*/
export class EventEmitter<EventMap extends { [s: string]: any }> extends EventTarget {
#listeners: Map<any, Listener[]> = new Map()
listenerCount (type: string) {
const listeners = this.#listeners.get(type)
if (listeners == null) {
return 0
}
return listeners.length
}
addEventListener<K extends keyof EventMap>(type: K, listener: EventHandler<EventMap[K]> | null, options?: boolean | AddEventListenerOptions): void
addEventListener (type: string, listener: EventHandler<Event>, options?: boolean | AddEventListenerOptions): void {
super.addEventListener(type, listener, options)
let list = this.#listeners.get(type)
if (list == null) {
list = []
this.#listeners.set(type, list)
}
list.push({
callback: listener,
once: (options !== true && options !== false && options?.once) ?? false
})
}
removeEventListener<K extends keyof EventMap>(type: K, listener?: EventHandler<EventMap[K]> | null, options?: boolean | EventListenerOptions): void
removeEventListener (type: string, listener?: EventHandler<Event>, options?: boolean | EventListenerOptions): void {
super.removeEventListener(type.toString(), listener ?? null, options)
let list = this.#listeners.get(type)
if (list == null) {
return
}
list = list.filter(({ callback }) => callback !== listener)
this.#listeners.set(type, list)
}
dispatchEvent (event: Event): boolean {
const result = super.dispatchEvent(event)
let list = this.#listeners.get(event.type)
if (list == null) {
return result
}
list = list.filter(({ once }) => !once)
this.#listeners.set(event.type, list)
return result
}
}
/**
* CustomEvent is a standard event but it's not supported by node.
*
* Remove this when https://github.com/nodejs/node/issues/40678 is closed.
*
* Ref: https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent
*/
class CustomEventPolyfill<T = any> extends Event {
/** Returns any custom data event was created with. Typically used for synthetic events. */
public detail: T
constructor (message: string, data?: EventInit & { detail: T }) {
super(message, data)
// @ts-expect-error could be undefined
this.detail = data?.detail
}
}
export const CustomEvent = globalThis.CustomEvent ?? CustomEventPolyfill