Commit 7535db377f995c4c82944c74c7e1cd3d51eb6c55
Committed by
GitHub
1 parent
a0fdceea
fix(utils): deepMerge failing to correctly merge basic data types (#2872)
Showing
2 changed files
with
52 additions
and
26 deletions
src/utils/__test__/index.test.ts
... | ... | @@ -4,6 +4,30 @@ import { describe, expect, test } from 'vitest'; |
4 | 4 | import { deepMerge } from '@/utils'; |
5 | 5 | |
6 | 6 | describe('deepMerge function', () => { |
7 | + test('should correctly merge basic data types', () => { | |
8 | + const source = { a: 1, b: 2, c: null }; | |
9 | + const target = { | |
10 | + a: 2, | |
11 | + b: undefined, | |
12 | + c: 3, | |
13 | + }; | |
14 | + const expected = { | |
15 | + a: 2, | |
16 | + b: 2, | |
17 | + c: 3, | |
18 | + }; | |
19 | + expect(deepMerge(source, target)).toStrictEqual(expected); | |
20 | + }); | |
21 | + | |
22 | + test('should return the same date if only 1 is passed', () => { | |
23 | + const foo = new Date(); | |
24 | + const merged = deepMerge(foo, null); | |
25 | + const merged2 = deepMerge(undefined, foo); | |
26 | + expect(merged).toStrictEqual(foo); | |
27 | + expect(merged2).toStrictEqual(foo); | |
28 | + expect(merged).toStrictEqual(merged2); | |
29 | + }); | |
30 | + | |
7 | 31 | test('should merge two objects recursively', () => { |
8 | 32 | const source = { |
9 | 33 | a: { b: { c: 1 }, d: [1, 2] }, |
... | ... | @@ -15,6 +39,7 @@ describe('deepMerge function', () => { |
15 | 39 | too: [1, 2, 3], |
16 | 40 | }, |
17 | 41 | ], |
42 | + r: { a: 1 }, | |
18 | 43 | }; |
19 | 44 | const target = { |
20 | 45 | a: { b: { d: [3] } }, |
... | ... | @@ -30,6 +55,7 @@ describe('deepMerge function', () => { |
30 | 55 | really: 'yes', |
31 | 56 | }, |
32 | 57 | ], |
58 | + r: { a: 2 }, | |
33 | 59 | }; |
34 | 60 | const expected = { |
35 | 61 | a: { b: { c: 1, d: [3] }, d: [1, 2] }, |
... | ... | @@ -48,8 +74,9 @@ describe('deepMerge function', () => { |
48 | 74 | }, |
49 | 75 | ], |
50 | 76 | qu: 5, |
77 | + r: { a: 2 }, | |
51 | 78 | }; |
52 | - expect(deepMerge(source, target)).toEqual(expected); | |
79 | + expect(deepMerge(source, target)).toStrictEqual(expected); | |
53 | 80 | }); |
54 | 81 | |
55 | 82 | test('should replace arrays by default', () => { |
... | ... | @@ -65,7 +92,7 @@ describe('deepMerge function', () => { |
65 | 92 | a: { b: { d: [3] } }, |
66 | 93 | e: [3], |
67 | 94 | }; |
68 | - expect(deepMerge(source, target)).toEqual(expected); | |
95 | + expect(deepMerge(source, target)).toStrictEqual(expected); | |
69 | 96 | }); |
70 | 97 | |
71 | 98 | test("should union arrays using mergeArrays = 'union'", () => { |
... | ... | @@ -75,13 +102,13 @@ describe('deepMerge function', () => { |
75 | 102 | }; |
76 | 103 | const target = { |
77 | 104 | a: { b: { d: [2, 3] } }, |
78 | - e: [3], | |
105 | + e: [1, 3], | |
79 | 106 | }; |
80 | 107 | const expected = { |
81 | 108 | a: { b: { d: [1, 2, 3] } }, |
82 | 109 | e: [1, 2, 3], |
83 | 110 | }; |
84 | - expect(deepMerge(source, target, 'union')).toEqual(expected); | |
111 | + expect(deepMerge(source, target, 'union')).toStrictEqual(expected); | |
85 | 112 | }); |
86 | 113 | |
87 | 114 | test("should intersect arrays using mergeArrays = 'intersection'", () => { |
... | ... | @@ -97,7 +124,7 @@ describe('deepMerge function', () => { |
97 | 124 | a: { b: { d: [2] } }, |
98 | 125 | e: [], |
99 | 126 | }; |
100 | - expect(deepMerge(source, target, 'intersection')).toEqual(expected); | |
127 | + expect(deepMerge(source, target, 'intersection')).toStrictEqual(expected); | |
101 | 128 | }); |
102 | 129 | |
103 | 130 | test("should concatenate arrays using mergeArrays = 'concat'", () => { |
... | ... | @@ -113,6 +140,6 @@ describe('deepMerge function', () => { |
113 | 140 | a: { b: { d: [1, 2, 2, 3] } }, |
114 | 141 | e: [1, 2, 3], |
115 | 142 | }; |
116 | - expect(deepMerge(source, target, 'concat')).toEqual(expected); | |
143 | + expect(deepMerge(source, target, 'concat')).toStrictEqual(expected); | |
117 | 144 | }); |
118 | 145 | }); | ... | ... |
src/utils/index.ts
... | ... | @@ -58,27 +58,26 @@ export function deepMerge<T extends object | null | undefined, U extends object |
58 | 58 | if (!source) { |
59 | 59 | return target as T & U; |
60 | 60 | } |
61 | - if (isArray(target) && isArray(source)) { | |
62 | - switch (mergeArrays) { | |
63 | - case 'union': | |
64 | - return unionWith(target, source, isEqual) as T & U; | |
65 | - case 'intersection': | |
66 | - return intersectionWith(target, source, isEqual) as T & U; | |
67 | - case 'concat': | |
68 | - return target.concat(source) as T & U; | |
69 | - case 'replace': | |
70 | - return source as T & U; | |
71 | - default: | |
72 | - throw new Error(`Unknown merge array strategy: ${mergeArrays}`); | |
73 | - | |
61 | + return mergeWith({}, source, target, (sourceValue, targetValue) => { | |
62 | + if (isArray(targetValue) && isArray(sourceValue)) { | |
63 | + switch (mergeArrays) { | |
64 | + case 'union': | |
65 | + return unionWith(sourceValue, targetValue, isEqual); | |
66 | + case 'intersection': | |
67 | + return intersectionWith(sourceValue, targetValue, isEqual); | |
68 | + case 'concat': | |
69 | + return sourceValue.concat(targetValue); | |
70 | + case 'replace': | |
71 | + return targetValue; | |
72 | + default: | |
73 | + throw new Error(`Unknown merge array strategy: ${mergeArrays as string}`); | |
74 | + } | |
74 | 75 | } |
75 | - } | |
76 | - if (isObject(target) && isObject(source)) { | |
77 | - return mergeWith({}, target, source, (targetValue, sourceValue) => { | |
78 | - return deepMerge(targetValue, sourceValue, mergeArrays); | |
79 | - }) as T & U; | |
80 | - } | |
81 | - return source as T & U; | |
76 | + if (isObject(targetValue) && isObject(sourceValue)) { | |
77 | + return deepMerge(sourceValue, targetValue, mergeArrays); | |
78 | + } | |
79 | + return undefined; | |
80 | + }); | |
82 | 81 | } |
83 | 82 | |
84 | 83 | export function openWindow( | ... | ... |