-
Notifications
You must be signed in to change notification settings - Fork 1.3k
/
updatable-target-proxy.ts
106 lines (85 loc) · 2.57 KB
/
updatable-target-proxy.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
98
99
100
101
102
103
104
105
106
/**
* Returns a read-only proxy that just forwards everything to a target,
* and a function that can be used to change that underlying target
*/
export function createUpdatableTargetProxy<T extends object>(
initialTarget: T
): {
proxy: T;
setTarget: (target: T) => void;
} {
const targetObject = {
target: initialTarget,
};
let isExtensible = Object.isExtensible(initialTarget);
const handler: Required<ProxyHandler<T>> = {
// these two functions are implemented because of the Required<ProxyHandler> type
apply(_, _thisArg, _argArray) {
throw new Error(
"cannot be implemented because the target is not a function"
);
},
construct(_, _argArray, _newTarget) {
throw new Error(
"cannot be implemented because the target is not a function"
);
},
defineProperty(_, property, _descriptor) {
throw new Error(
`cannot define property ${String(property)} in read-only proxy`
);
},
deleteProperty(_, property) {
throw new Error(
`cannot delete property ${String(property)} in read-only proxy`
);
},
get(_, property, receiver) {
const result = Reflect.get(targetObject.target, property, receiver);
if (result instanceof Function) {
return result.bind(targetObject.target);
}
return result;
},
getOwnPropertyDescriptor(_, property) {
const descriptor = Reflect.getOwnPropertyDescriptor(
targetObject.target,
property
);
if (descriptor !== undefined) {
Object.defineProperty(targetObject.target, property, descriptor);
}
return descriptor;
},
getPrototypeOf(_) {
return Reflect.getPrototypeOf(targetObject.target);
},
has(_, property) {
return Reflect.has(targetObject.target, property);
},
isExtensible(_) {
// we need to return the extensibility value of the original target
return isExtensible;
},
ownKeys(_) {
return Reflect.ownKeys(targetObject.target);
},
preventExtensions(_) {
isExtensible = false;
return Reflect.preventExtensions(targetObject.target);
},
set(_, property, _value, _receiver) {
throw new Error(
`cannot set property ${String(property)} in read-only proxy`
);
},
setPrototypeOf(_, _prototype) {
throw new Error("cannot change the prototype in read-only proxy");
},
};
const proxy: T = new Proxy(initialTarget, handler);
const setTarget = (newTarget: T) => {
targetObject.target = newTarget;
};
return { proxy, setTarget };
}