Skip to content

Instantly share code, notes, and snippets.

@arleighdickerson
Last active July 9, 2023 16:29
Show Gist options
  • Select an option

  • Save arleighdickerson/bbf986330425dde4e8d5e167681bbd79 to your computer and use it in GitHub Desktop.

Select an option

Save arleighdickerson/bbf986330425dde4e8d5e167681bbd79 to your computer and use it in GitHub Desktop.
import { DelegatingHandler } from './proxy-handlers';
import _ from 'lodash';
function GhostObject<T>(thunk: () => T) {
// @ts-ignore
this.thunk = thunk;
// @ts-ignore
this.val = undefined;
}
GhostObject.prototype = Object.create(DelegatingHandler.prototype);
GhostObject.prototype.force = function () {
try {
if (this.thunk !== null) {
[this.val, this.thunk] = [this.thunk.call(undefined), null];
}
} catch (e) {
console.error(e);
}
};
const traps = [
'get',
'set',
'apply',
'ownKeys',
'construct',
'preventExtensions',
'setPrototypeOf',
'has',
'defineProperty',
'deleteProperty',
'getPrototypeOf',
'isExtensible',
'getOwnPropertyDescriptor',
];
traps.forEach(name => {
GhostObject.prototype[name] = function trap(target: any, ...args: any) {
this.force();
return _.invoke(Reflect, name, this.val, ...args);
};
});
export const singletonize = <T>(factory: () => T) => {
let initialized: boolean = false;
let result: T;
return (): T => {
if (!initialized) {
[initialized, result] = [true, factory()];
}
return result;
};
};
export default function createGhostObject<T>(factory: () => T, singleton: boolean = true): T {
return DelegatingHandler.proxyFor.call(GhostObject, {}, singleton ? singletonize(factory) : factory);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment