-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
/
Copy patheventEmitterWithPromise.ts
82 lines (75 loc) · 2.05 KB
/
eventEmitterWithPromise.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
import EventEmitter from "eventemitter3";
import logger from "./logger";
import { PeerError, PromiseEvents } from "./peerError";
export class EventEmitterWithPromise<
AwaitType extends EventEmitter<Events>,
OpenType,
ErrorType extends string,
Events extends PromiseEvents<OpenType, ErrorType>,
>
extends EventEmitter<Events | PromiseEvents<OpenType, ErrorType>, never>
implements Promise<AwaitType>
{
protected _open = false;
readonly [Symbol.toStringTag]: string;
catch<TResult = never>(
onrejected?:
| ((reason: PeerError<`${ErrorType}`>) => PromiseLike<TResult> | TResult)
| undefined
| null,
): Promise<AwaitType | TResult> {
return this.then(undefined, onrejected);
}
finally(onfinally?: (() => void) | undefined | null): Promise<AwaitType> {
return this.then().finally(onfinally);
}
then<TResult1 = AwaitType, TResult2 = never>(
onfulfilled?:
| ((value: AwaitType) => PromiseLike<TResult1> | TResult1)
| undefined
| null,
onrejected?:
| ((reason: any) => PromiseLike<TResult2> | TResult2)
| undefined
| null,
): Promise<TResult1 | TResult2> {
const p = new Promise((resolve, reject) => {
const onOpen = () => {
this.off("error", onError);
// Remove 'then' to prevent potential recursion issues
// `await` will wait for a Promise-like to resolve recursively
resolve?.(proxyWithoutThen(this));
};
const onError = (err: PeerError<`${ErrorType}`>) => {
this.off("open", onOpen);
reject(err);
};
if (this._open) {
onOpen();
return;
}
this.once("open", onOpen);
this.once("error", onError);
});
return p.then(onfulfilled, onrejected);
}
/**
* Emits a typed error message.
*
* @internal
*/
emitError(type: ErrorType, err: string | Error): void {
logger.error("Error:", err);
this.emit("error", new PeerError<`${ErrorType}`>(`${type}`, err));
}
}
function proxyWithoutThen<T extends object>(obj: T) {
return new Proxy(obj, {
get(target, p, receiver) {
if (p === "then") {
return undefined;
}
return Reflect.get(target, p, receiver);
},
});
}