-
Notifications
You must be signed in to change notification settings - Fork 25
/
proxies.ts
65 lines (61 loc) · 2.04 KB
/
proxies.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
import Decimal from "./bignum";
export const ProxyState = Symbol("ProxyState");
export const ProxyPath = Symbol("ProxyPath");
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type ProxiedWithState<T> = NonNullable<T> extends Record<PropertyKey, any>
? NonNullable<T> extends Decimal
? T
: {
[K in keyof T]: ProxiedWithState<T[K]>;
} & {
[ProxyState]: T;
[ProxyPath]: string[];
}
: T;
// Takes a function that returns an object and pretends to be that object
// Note that the object is lazily calculated
export function createLazyProxy<T extends object, S>(
objectFunc: (baseObject: S) => T & S,
baseObject: S = {} as S
): T {
const obj: S & Partial<T> = baseObject;
let calculated = false;
function calculateObj(): T {
if (!calculated) {
Object.assign(obj, objectFunc(obj));
calculated = true;
}
return obj as S & T;
}
return new Proxy(obj, {
get(target, key) {
if (key === ProxyState) {
return calculateObj();
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return (calculateObj() as any)[key];
},
set(target, key, value) {
// TODO give warning about this? It should only be done with caution
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(calculateObj() as any)[key] = value;
return true;
},
has(target, key) {
if (key === ProxyState) {
return true;
}
return Reflect.has(calculateObj(), key);
},
ownKeys() {
return Reflect.ownKeys(calculateObj());
},
getOwnPropertyDescriptor(target, key) {
if (!calculated) {
Object.assign(obj, objectFunc(obj));
calculated = true;
}
return Object.getOwnPropertyDescriptor(target, key);
}
}) as S & T;
}