-
Notifications
You must be signed in to change notification settings - Fork 3
/
index.ts
54 lines (45 loc) · 1.33 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
interface SafeCallable<T> {
(): T | undefined;
<K>(fallback: K): K | T;
}
type SafeProps<T> = {
readonly [P in keyof T]-?: SafeTouch<T[P]>;
} & {
[P: string]: SafeTouch<any>;
};
type Safe<T> = SafeProps<T> & SafeCallable<T>;
type SafeTouch<T> = T extends undefined | number | boolean
? Safe<any>
: Safe<T>;
interface SafeProxyHandler<T> {
get<K extends keyof T>(target: T, p: K): SafeTouch<T[K]>;
apply(target: any, thisArg: any, argList: any[]): T;
}
function applyWithFallback<T>(original: T): SafeProxyHandler<T>["apply"] {
return function tryFallback(_, __, [fallback]) {
return original === undefined ? fallback : original;
};
}
function noop() {}
// Using var to prevent circular referencing error on the first call
var blackHole = touch(undefined);
function touch(source?: undefined): SafeTouch<any>;
function touch<T>(source: T): SafeTouch<T>;
function touch(source: any) {
if (typeof source === "undefined" && typeof blackHole !== "undefined")
return blackHole;
return new Proxy(noop, {
apply: applyWithFallback(source),
get: (_, key) => {
if (
source !== undefined &&
source !== null &&
Object.prototype.hasOwnProperty.call(source, key)
)
return touch(source[key]);
return blackHole;
},
});
}
export const safeTouch = touch;
export default touch;