Skip to content

Commit e0bc088

Browse files
committed
minor(@repo/utils): update deepMerge types
1 parent 688bd53 commit e0bc088

1 file changed

Lines changed: 32 additions & 17 deletions

File tree

packages/utils/src/std/objects.ts

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
type Key = string | number | symbol;
2-
type GenericObject<A> = Record<Key, A>;
2+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
3+
type IsObject<T> = T extends object ? (T extends Array<any> ? false : true) : false;
4+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
5+
type GenericObject = object | Array<any>;
6+
type Merge<T, U> = IsObject<T> & IsObject<U> extends true
7+
? {
8+
[K in keyof T]: K extends keyof U ? Merge<T[K], U[K]> : T[K];
9+
} & U
10+
: U;
311

412
class ObjectFunctor<T extends Record<PropertyKey, unknown>> {
513
public constructor(private readonly internal: T) {}
@@ -47,24 +55,31 @@ class ObjectFunctor<T extends Record<PropertyKey, unknown>> {
4755
}
4856
}
4957

50-
function isRecord(value: unknown): value is GenericObject<unknown> {
51-
return typeof value === "object" && value !== null && !Array.isArray(value);
58+
function isRecord<T>(v: T): IsObject<T> {
59+
return (typeof v === "object" && v !== null && !Array.isArray(v)) as IsObject<T>;
5260
}
5361

54-
function deepMerge<A, B>(a: GenericObject<A>, b: GenericObject<B>): GenericObject<A | B> {
55-
const result: GenericObject<A | B> = { ...a };
56-
57-
for (const [key, value] of Object.entries(b)) {
58-
if (isRecord(result[key]) && isRecord(value)) {
59-
result[key] = deepMerge(result[key], value) as A | B;
60-
} else if (Array.isArray(result[key]) && Array.isArray(value)) {
61-
result[key] = [...result[key], ...value] as A | B;
62-
} else {
63-
result[key] = value;
64-
}
65-
}
66-
67-
return result;
62+
function deepMerge<T extends object, U extends object>(
63+
a: T,
64+
b: U,
65+
{ mergeArrays = true }: { mergeArrays?: boolean } = {},
66+
): Merge<T, U> {
67+
return (
68+
isRecord(a) && isRecord(b)
69+
? Object.assign(
70+
{},
71+
a,
72+
Object.fromEntries(
73+
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access
74+
Object.entries(b).map(([k, v]) => [k, deepMerge((a as any)[k], v, { mergeArrays })]),
75+
),
76+
)
77+
: Array.isArray(a) && Array.isArray(b)
78+
? mergeArrays
79+
? [...a, ...b]
80+
: b
81+
: b
82+
) as Merge<T, U>;
6883
}
6984

7085
export { deepMerge, isRecord, ObjectFunctor };

0 commit comments

Comments
 (0)