import Decimal from "util/bignum"; export const ProxyState = Symbol("ProxyState"); export const ProxyPath = Symbol("ProxyPath"); // eslint-disable-next-line @typescript-eslint/no-explicit-any export type ProxiedWithState = NonNullable extends Record ? NonNullable extends Decimal ? T : { [K in keyof T]: ProxiedWithState; } & { [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( objectFunc: (baseObject: S) => T & S, baseObject: S = {} as S ): T { const obj: S & Partial = 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; }