Skip to content

Instantly share code, notes, and snippets.

@teramuza
Created December 27, 2024 03:29
Show Gist options
  • Save teramuza/341ce6f442885ac921d2ca9c4bea1e81 to your computer and use it in GitHub Desktop.
Save teramuza/341ce6f442885ac921d2ca9c4bea1e81 to your computer and use it in GitHub Desktop.
Patching updated data overriding values in `base` with non-empty values from `patch`
/**
* Merges two objects (`base` and `patch`) by overriding values in `base` with non-empty values from `patch`.
*
* - If a value in `patch` is `null`, `undefined`, or an empty string (`""`), the corresponding value from `base` is used.
* - For nested objects, the function performs a recursive merge.
*
* This function is useful for scenarios where default values (`base`) need to be preserved unless explicitly replaced
* by valid values from another source (`patch`).
*
* @template T - The type of the objects being merged. Defaults to `object`.
* @param {T} base - The base object containing default values.
* @param {T} patch - The object containing values to override those in `base`.
* @returns {T} - A new object that combines properties from `base` and `patch`.
*
* @example
* // Simple merge
* const base = { name: "John", age: 30 };
* const patch = { name: "", age: 25 };
* const result = patchObject(base, patch);
* console.log(result); // { name: "John", age: 25 }
*
* @example
* // Nested merge
* const baseNested = { name: "John", details: { city: "New York", phone: "12345" } };
* const patchNested = { name: "", details: { city: "Los Angeles" } };
* const resultNested = patchObject(baseNested, patchNested);
* console.log(resultNested);
* // Output:
* // { name: "John", details: { city: "Los Angeles", phone: "12345" } }
*/
export function patchObject<T extends Record<string, unknown>>(
base: T = {} as T,
patch: T = {} as T,
): T {
const result = { ...base };
Object.keys(patch).forEach((key) => {
const patchValue = patch[key as keyof T];
const baseValue = base[key as keyof T];
if (
patchValue === null ||
patchValue === '' ||
patchValue === undefined
) {
result[key as keyof T] = baseValue;
} else if (
typeof patchValue === 'object' &&
!Array.isArray(patchValue)
) {
result[key as keyof T] = patchObject(
(baseValue || {}) as Record<string, unknown>,
patchValue as Record<string, unknown>,
) as T[keyof T];
} else {
result[key as keyof T] = patchValue;
}
});
return result;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment