fix(utils): deepMerge failing to correctly merge basic data types (#2872)

This commit is contained in:
Kirk Lin 2023-06-19 16:59:44 +08:00 committed by GitHub
parent a0fdceeae7
commit 7535db377f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 52 additions and 26 deletions

View File

@ -4,6 +4,30 @@ import { describe, expect, test } from 'vitest';
import { deepMerge } from '@/utils'; import { deepMerge } from '@/utils';
describe('deepMerge function', () => { describe('deepMerge function', () => {
test('should correctly merge basic data types', () => {
const source = { a: 1, b: 2, c: null };
const target = {
a: 2,
b: undefined,
c: 3,
};
const expected = {
a: 2,
b: 2,
c: 3,
};
expect(deepMerge(source, target)).toStrictEqual(expected);
});
test('should return the same date if only 1 is passed', () => {
const foo = new Date();
const merged = deepMerge(foo, null);
const merged2 = deepMerge(undefined, foo);
expect(merged).toStrictEqual(foo);
expect(merged2).toStrictEqual(foo);
expect(merged).toStrictEqual(merged2);
});
test('should merge two objects recursively', () => { test('should merge two objects recursively', () => {
const source = { const source = {
a: { b: { c: 1 }, d: [1, 2] }, a: { b: { c: 1 }, d: [1, 2] },
@ -15,6 +39,7 @@ describe('deepMerge function', () => {
too: [1, 2, 3], too: [1, 2, 3],
}, },
], ],
r: { a: 1 },
}; };
const target = { const target = {
a: { b: { d: [3] } }, a: { b: { d: [3] } },
@ -30,6 +55,7 @@ describe('deepMerge function', () => {
really: 'yes', really: 'yes',
}, },
], ],
r: { a: 2 },
}; };
const expected = { const expected = {
a: { b: { c: 1, d: [3] }, d: [1, 2] }, a: { b: { c: 1, d: [3] }, d: [1, 2] },
@ -48,8 +74,9 @@ describe('deepMerge function', () => {
}, },
], ],
qu: 5, qu: 5,
r: { a: 2 },
}; };
expect(deepMerge(source, target)).toEqual(expected); expect(deepMerge(source, target)).toStrictEqual(expected);
}); });
test('should replace arrays by default', () => { test('should replace arrays by default', () => {
@ -65,7 +92,7 @@ describe('deepMerge function', () => {
a: { b: { d: [3] } }, a: { b: { d: [3] } },
e: [3], e: [3],
}; };
expect(deepMerge(source, target)).toEqual(expected); expect(deepMerge(source, target)).toStrictEqual(expected);
}); });
test("should union arrays using mergeArrays = 'union'", () => { test("should union arrays using mergeArrays = 'union'", () => {
@ -75,13 +102,13 @@ describe('deepMerge function', () => {
}; };
const target = { const target = {
a: { b: { d: [2, 3] } }, a: { b: { d: [2, 3] } },
e: [3], e: [1, 3],
}; };
const expected = { const expected = {
a: { b: { d: [1, 2, 3] } }, a: { b: { d: [1, 2, 3] } },
e: [1, 2, 3], e: [1, 2, 3],
}; };
expect(deepMerge(source, target, 'union')).toEqual(expected); expect(deepMerge(source, target, 'union')).toStrictEqual(expected);
}); });
test("should intersect arrays using mergeArrays = 'intersection'", () => { test("should intersect arrays using mergeArrays = 'intersection'", () => {
@ -97,7 +124,7 @@ describe('deepMerge function', () => {
a: { b: { d: [2] } }, a: { b: { d: [2] } },
e: [], e: [],
}; };
expect(deepMerge(source, target, 'intersection')).toEqual(expected); expect(deepMerge(source, target, 'intersection')).toStrictEqual(expected);
}); });
test("should concatenate arrays using mergeArrays = 'concat'", () => { test("should concatenate arrays using mergeArrays = 'concat'", () => {
@ -113,6 +140,6 @@ describe('deepMerge function', () => {
a: { b: { d: [1, 2, 2, 3] } }, a: { b: { d: [1, 2, 2, 3] } },
e: [1, 2, 3], e: [1, 2, 3],
}; };
expect(deepMerge(source, target, 'concat')).toEqual(expected); expect(deepMerge(source, target, 'concat')).toStrictEqual(expected);
}); });
}); });

View File

@ -58,27 +58,26 @@ export function deepMerge<T extends object | null | undefined, U extends object
if (!source) { if (!source) {
return target as T & U; return target as T & U;
} }
if (isArray(target) && isArray(source)) { return mergeWith({}, source, target, (sourceValue, targetValue) => {
if (isArray(targetValue) && isArray(sourceValue)) {
switch (mergeArrays) { switch (mergeArrays) {
case 'union': case 'union':
return unionWith(target, source, isEqual) as T & U; return unionWith(sourceValue, targetValue, isEqual);
case 'intersection': case 'intersection':
return intersectionWith(target, source, isEqual) as T & U; return intersectionWith(sourceValue, targetValue, isEqual);
case 'concat': case 'concat':
return target.concat(source) as T & U; return sourceValue.concat(targetValue);
case 'replace': case 'replace':
return source as T & U; return targetValue;
default: default:
throw new Error(`Unknown merge array strategy: ${mergeArrays}`); throw new Error(`Unknown merge array strategy: ${mergeArrays as string}`);
} }
} }
if (isObject(target) && isObject(source)) { if (isObject(targetValue) && isObject(sourceValue)) {
return mergeWith({}, target, source, (targetValue, sourceValue) => { return deepMerge(sourceValue, targetValue, mergeArrays);
return deepMerge(targetValue, sourceValue, mergeArrays);
}) as T & U;
} }
return source as T & U; return undefined;
});
} }
export function openWindow( export function openWindow(