wardens
Version:
A framework for resource management
52 lines (43 loc) • 1.6 kB
text/typescript
/**
* The framework's usage of proxies can cause havoc on classes that depend on
* true private fields, such as Map, Set, and some networking classes in Node's
* core library, among others. If you run into those challenges, `bindContext`
* can dynamically correct the errors by retargeting the `this` context to the
* original value.
*
* Contexts aren't rebound by default because it has a noticeable side-effect:
* method identity is no longer the same. This can be very irritating in unit
* tests that assert a stable function identity.
*
* Example:
*
* exports = () => bindContext(new Set())
*
*/
export default function bindContext<T extends object>(value: T) {
const methodBindings = new WeakMap<object, AnyMethod>();
return new Proxy(value, {
get(target, property) {
const value = Reflect.get(target, property, target);
// Bind methods to the real `this` context while maintaining
// a consistent function identity.
if (typeof value === 'function') {
if (methodBindings.has(value) === false) {
const methodBinding = value.bind(target);
// Copy static function properties.
Object.defineProperties(
methodBinding,
Object.getOwnPropertyDescriptors(value),
);
methodBindings.set(value, methodBinding);
}
return methodBindings.get(value);
}
return value;
},
set(target, property, newValue) {
return Reflect.set(target, property, newValue, target);
},
});
}
type AnyMethod = (...args: Array<unknown>) => unknown;