1import * as P from "effect/Predicate";
2
3export type DeepPartial<T> = T extends readonly (infer U)[]
4 ? readonly DeepPartial<U>[]
5 : T extends object
6 ? { [K in keyof T]?: DeepPartial<T[K]> }
7 : T;
8
9export function deepMerge<T extends Record<string, unknown>>(current: T, patch: DeepPartial<T>): T {
10 if (!P.isObject(current) || !P.isObject(patch)) {
11 return patch as T;
12 }
13
14 const next = { ...current } as Record<string, unknown>;
15 for (const [key, value] of Object.entries(patch)) {
16 if (value === undefined) continue;
17
18 const existing = next[key];
19 next[key] = P.isObject(existing) && P.isObject(value) ? deepMerge(existing, value) : value;
20 }
21
22 return next as T;
23}