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.

Revisions

  1. teramuza created this gist Dec 27, 2024.
    61 changes: 61 additions & 0 deletions ObjectUtils.ts
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,61 @@
    /**
    * 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;
    }