61 lines
1.9 KiB
TypeScript
61 lines
1.9 KiB
TypeScript
import { clonePlain } from './clone-plain';
|
|
|
|
export class MutationProxy<T extends object> {
|
|
|
|
private readonly getOriginal: () => T;
|
|
private readonly getMutated: () => Partial<T>;
|
|
|
|
constructor(
|
|
getOriginal: () => T,
|
|
getMutated: () => Partial<T>,
|
|
) {
|
|
this.getOriginal = getOriginal;
|
|
this.getMutated = getMutated;
|
|
}
|
|
|
|
create(): T {
|
|
return new Proxy({} as T, {
|
|
get: (_target, prop: string | symbol) => {
|
|
if (typeof prop !== 'string') {
|
|
return undefined;
|
|
}
|
|
|
|
const key = prop as keyof T;
|
|
const mutated = this.getMutated();
|
|
const original = this.getOriginal();
|
|
return key in mutated ? mutated[key] : original[key];
|
|
},
|
|
set: (_target, prop: string | symbol, value: unknown) => {
|
|
if (typeof prop === 'string') {
|
|
const key = prop as keyof T;
|
|
(this.getMutated() as Record<keyof T, unknown>)[key] = clonePlain(value);
|
|
}
|
|
|
|
return true;
|
|
},
|
|
has: (_target, prop: string | symbol) => {
|
|
if (typeof prop !== 'string') {
|
|
return false;
|
|
}
|
|
|
|
const mutated = this.getMutated();
|
|
const original = this.getOriginal();
|
|
return prop in mutated || prop in original;
|
|
},
|
|
ownKeys: () => {
|
|
const mutated = this.getMutated();
|
|
const original = this.getOriginal();
|
|
|
|
return Array.from(new Set([
|
|
...Reflect.ownKeys(original),
|
|
...Reflect.ownKeys(mutated),
|
|
]));
|
|
},
|
|
getOwnPropertyDescriptor: () => ({
|
|
enumerable: true,
|
|
configurable: true,
|
|
}),
|
|
});
|
|
}
|
|
|
|
} |