|
| 1 | +import type { DeepMerge, SimplifyDeep } from './types' |
| 2 | + |
1 | 3 | /**
|
2 |
| - * Deep merge objects or arrays |
| 4 | + * Deep Merge |
| 5 | + * |
| 6 | + * Merges arrays if both configs are arrays, otherwise does object deep merge. |
3 | 7 | *
|
4 |
| - * @param target - The target object or array |
5 |
| - * @param sources - The source objects or arrays |
6 |
| - * @returns The merged result |
| 8 | + * @param target - The target object. |
| 9 | + * @param sources - The source objects. |
| 10 | + * @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 | + * ``` |
7 | 16 | */
|
8 |
| -export function deepMerge<T>(target: T, ...sources: Partial<T>[]): T { |
| 17 | +export function deepMerge<T, S>(target: T, ...sources: S[]): T extends object |
| 18 | + ? S extends any[] |
| 19 | + ? S |
| 20 | + : S extends object |
| 21 | + ? SimplifyDeep<DeepMerge<T, S>> |
| 22 | + : T |
| 23 | + : T extends any[] |
| 24 | + ? S extends any[] |
| 25 | + ? T |
| 26 | + : T |
| 27 | + : T { |
9 | 28 | if (!sources.length)
|
10 |
| - return target |
| 29 | + return target as any |
11 | 30 |
|
12 | 31 | const source = sources.shift()
|
13 | 32 | if (!source)
|
14 |
| - return target |
| 33 | + return target as any |
| 34 | + |
| 35 | + if (Array.isArray(source) !== Array.isArray(target) |
| 36 | + || isObject(source) !== isObject(target)) { |
| 37 | + return source as any |
| 38 | + } |
15 | 39 |
|
16 | 40 | if (Array.isArray(target) && Array.isArray(source)) {
|
17 |
| - // If both are arrays, concatenate them |
18 |
| - return [...target, ...source] as T |
| 41 | + return [...target, ...source] as any |
19 | 42 | }
|
20 | 43 |
|
21 | 44 | if (isObject(target) && isObject(source)) {
|
22 | 45 | for (const key in source) {
|
23 | 46 | if (Object.prototype.hasOwnProperty.call(source, key)) {
|
24 | 47 | const sourceValue = source[key]
|
25 |
| - if (Array.isArray(sourceValue) && Array.isArray((target as any)[key])) { |
26 |
| - // Merge arrays within objects |
27 |
| - (target as any)[key] = [...(target as any)[key], ...sourceValue] |
28 |
| - } |
29 |
| - else if (isObject(sourceValue) && isObject((target as any)[key])) { |
30 |
| - // Deep merge nested objects |
31 |
| - (target as any)[key] = deepMerge((target as any)[key], sourceValue) |
32 |
| - } |
33 |
| - else { |
34 |
| - // Replace primitive values and objects/arrays that don't match in type |
| 48 | + if (!Object.prototype.hasOwnProperty.call(target, key)) { |
35 | 49 | (target as any)[key] = sourceValue
|
| 50 | + continue |
36 | 51 | }
|
| 52 | + |
| 53 | + (target as any)[key] = deepMerge((target as any)[key], sourceValue) |
37 | 54 | }
|
38 | 55 | }
|
39 | 56 | }
|
|
0 commit comments