ts-merge-patch
Version:
Typescript-ready version of RFC7396 Merge Patch
51 lines (47 loc) • 1.97 kB
text/typescript
type mpObj<T> = { [k in keyof T | string | number | symbol]: any };
export function apply<L, R>(
target: mpObj<L>,
patchItem: mpObj<R>
): Partial<L> & Partial<R>;
export function apply<L, R>(target: mpObj<L>, patchItem: mpObj<R>): R;
export function apply<L, R>(target: mpObj<L>, patchItem: mpObj<R>): {};
export function apply<L, R>(target: mpObj<L>, patchItem: null): null;
export function apply<L, R>(target: mpObj<L>, patchItem: string): string;
export function apply<L, R>(target: mpObj<L>, patchItem: number): number;
export function apply<L, R>(target: mpObj<L>, patchItem: undefined): undefined;
export function apply<L, R>(target: mpObj<L>, patchItem: R[]): R[];
export function apply(target: any, patchItem: any): any {
/**
* If the patch is anything other than an object,
* the result will always be to replace
* the entire target with the entire patch.
*/
if (typeof patchItem !== "object" || Array.isArray(patchItem) || !patchItem) {
return JSON.parse(JSON.stringify(patchItem)); //return new instance of variable
}
if (
typeof patchItem === "object" &&
patchItem.toJSON !== undefined &&
typeof patchItem.toJSON === "function"
) {
return patchItem.toJSON();
}
/** Also, it is not possible to
* patch part of a target that is not an object,
* such as to replace just some of the values in an array.
*/
let targetResult = target;
if (typeof target !== "object") {
//Target is empty/not an object, so basically becomes patch, minus any null valued sections (becomes {} + patch)
targetResult = { ...patchItem };
}
Object.keys(patchItem).forEach((k) => {
if (!targetResult.hasOwnProperty(k)) targetResult[k] = patchItem[k]; //This ensure the key exists and TS can't throw a wobbly over an undefined key
if (patchItem[k] === null) {
delete targetResult[k];
} else {
targetResult[k] = apply(targetResult[k], patchItem[k]);
}
});
return targetResult;
}