-
Notifications
You must be signed in to change notification settings - Fork 57
/
Copy pathevent-emitter.ts
55 lines (53 loc) · 2.31 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
type EventMap = Record<string, Event>;
type Listener<TEvent extends Event> = ((evt: TEvent) => void) | { handleEvent(object: TEvent): void };
/**
* This type allows you to type `addEventListener` and `removeEventListener` so that the call
* signature of the listener matches the event type given.
*
* @example
* ```ts
* const emitter: TypedEventEmitter<{ message: MessageEvent }> = new WebSocket('wss://api.devnet.solana.com');
* emitter.addEventListener('data', handleData); // ERROR. `data` is not a known event type.
* emitter.addEventListener('message', message => {
* console.log(message.origin); // OK. `message` is a `MessageEvent` so it has an `origin` property.
* });
* ```
*/
export interface TypedEventEmitter<TEventMap extends EventMap> {
addEventListener<const TEventType extends keyof TEventMap>(
type: TEventType,
listener: Listener<TEventMap[TEventType]>,
options?: AddEventListenerOptions | boolean,
): void;
removeEventListener<const TEventType extends keyof TEventMap>(
type: TEventType,
listener: Listener<TEventMap[TEventType]>,
options?: EventListenerOptions | boolean,
): void;
}
// Why not just extend the interface above, rather than to copy/paste it?
// See https://github.com/microsoft/TypeScript/issues/60008
/**
* This type is a superset of `TypedEventEmitter` that allows you to constrain calls to
* `dispatchEvent`.
*
* @example
* ```ts
* const target: TypedEventTarget<{ candyVended: CustomEvent<{ flavour: string }> }> = new EventTarget();
* target.dispatchEvent(new CustomEvent('candyVended', { detail: { flavour: 'raspberry' } })); // OK.
* target.dispatchEvent(new CustomEvent('candyVended', { detail: { flavor: 'raspberry' } })); // ERROR. Misspelling in detail.
* ```
*/
export interface TypedEventTarget<TEventMap extends EventMap> {
addEventListener<const TEventType extends keyof TEventMap>(
type: TEventType,
listener: Listener<TEventMap[TEventType]>,
options?: AddEventListenerOptions | boolean,
): void;
dispatchEvent<TEventType extends keyof TEventMap>(ev: TEventMap[TEventType]): void;
removeEventListener<const TEventType extends keyof TEventMap>(
type: TEventType,
listener: Listener<TEventMap[TEventType]>,
options?: EventListenerOptions | boolean,
): void;
}