Skip to content

Commit 6265797

Browse files
committed
fix: adjust deepMerge to handle arrays & objects properyl
chore: wip
1 parent 440f0f6 commit 6265797

File tree

1 file changed

+43
-37
lines changed

1 file changed

+43
-37
lines changed

src/utils.ts

+43-37
Original file line numberDiff line numberDiff line change
@@ -3,61 +3,67 @@ import type { DeepMerge, SimplifyDeep } from './types'
33
/**
44
* Deep Merge
55
*
6-
* Merges arrays if both configs are arrays, otherwise does object deep merge.
6+
* Merges two objects or arrays deeply.
77
*
8-
* @param target - The target object.
9-
* @param sources - The source objects.
8+
* @param target - The target object (default config).
9+
* @param source - The source objects (loaded configs that should override defaults).
1010
* @returns The merged object.
11-
* @example ```ts
12-
* deepMerge({ foo: 'bar' }, { bar: 'baz' })
13-
* deepMerge([{ foo: 'bar' }], [{ bar: 'baz' }])
14-
* deepMerge({ foo: 'bar' }, [{ foo: 'baz' }])
15-
* ```
1611
*/
17-
export function deepMerge<T, S>(target: T, ...sources: S[]): T extends object
12+
export function deepMerge<T, S>(target: T, source: S): T extends any[]
1813
? S extends any[]
19-
? S
20-
: S extends object
21-
? SimplifyDeep<DeepMerge<T, S>>
22-
: T
23-
: T extends any[]
14+
? Array<SimplifyDeep<DeepMerge<T[number], S[number]>>>
15+
: S
16+
: T extends object
2417
? S extends any[]
25-
? T
26-
: T
18+
? S
19+
: S extends object
20+
? SimplifyDeep<DeepMerge<T, S>>
21+
: T
2722
: T {
28-
if (!sources.length)
29-
return target as any
23+
// If source is an array but target isn't, return source
24+
if (Array.isArray(source) && !Array.isArray(target)) {
25+
return source as any
26+
}
3027

31-
const source = sources.shift()
32-
if (!source)
33-
return target as any
28+
// If both are arrays, merge their contents
29+
if (Array.isArray(source) && Array.isArray(target)) {
30+
return source.map((sourceItem, index) => {
31+
const targetItem = target[index]
32+
if (isObject(sourceItem) && isObject(targetItem)) {
33+
return deepMerge(targetItem, sourceItem)
34+
}
35+
return sourceItem
36+
}) as any
37+
}
3438

35-
if (Array.isArray(source) !== Array.isArray(target)
36-
|| isObject(source) !== isObject(target)) {
39+
// Handle non-objects (primitives)
40+
if (!isObject(source) || !isObject(target)) {
3741
return source as any
3842
}
3943

40-
if (Array.isArray(target) && Array.isArray(source)) {
41-
return [...target, ...source] as any
42-
}
44+
// Handle objects
45+
const merged = { ...target } as any
4346

44-
if (isObject(target) && isObject(source)) {
45-
for (const key in source) {
46-
if (Object.prototype.hasOwnProperty.call(source, key)) {
47-
const sourceValue = source[key]
48-
if (!Object.prototype.hasOwnProperty.call(target, key)) {
49-
(target as any)[key] = sourceValue
50-
continue
51-
}
47+
for (const key in source) {
48+
if (Object.prototype.hasOwnProperty.call(source, key)) {
49+
const sourceValue = source[key]
50+
const targetValue = merged[key]
5251

53-
(target as any)[key] = deepMerge((target as any)[key], sourceValue)
52+
if (sourceValue === null || sourceValue === undefined) {
53+
merged[key] = sourceValue
54+
}
55+
else if (isObject(sourceValue) && isObject(targetValue)) {
56+
merged[key] = deepMerge(targetValue, sourceValue)
57+
}
58+
else {
59+
merged[key] = sourceValue
5460
}
5561
}
5662
}
5763

58-
return deepMerge(target, ...sources)
64+
return merged
5965
}
6066

6167
function isObject(item: unknown): item is Record<string, unknown> {
62-
return (item && typeof item === 'object' && !Array.isArray(item)) as boolean
68+
return Boolean(item && typeof item === 'object' && !Array.isArray(item))
6369
}

0 commit comments

Comments
 (0)