Skip to content

Commit cac988e

Browse files
committed
feat: support deep merge
1 parent 4d24a06 commit cac988e

File tree

2 files changed

+59
-4
lines changed

2 files changed

+59
-4
lines changed

src/utils/set.ts

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,25 @@ function createEmpty<T>(source: T) {
6666

6767
const keys = typeof Reflect === 'undefined' ? Object.keys : Reflect.ownKeys;
6868

69+
// ================================ Merge ================================
70+
export type MergeFn = (srcVal: any, tgtVal: any) => any;
71+
6972
/**
70-
* Merge objects which will create
73+
* Merge multiple objects. Support custom merge logic.
74+
* @param sources object sources
75+
* @param config.prepareArray Customize array prepare function.
76+
* It will return empty [] by default.
77+
* So when match array, it will auto be override with next array in sources.
7178
*/
72-
export function merge<T extends object>(...sources: T[]) {
79+
export function deepMerge<T extends object>(
80+
sources: T[],
81+
config: {
82+
prepareArray?: MergeFn;
83+
} = {},
84+
) {
85+
const { prepareArray } = config;
86+
const finalPrepareArray: MergeFn = prepareArray || (() => []);
87+
7388
let clone = createEmpty(sources[0]);
7489

7590
sources.forEach(src => {
@@ -89,7 +104,7 @@ export function merge<T extends object>(...sources: T[]) {
89104

90105
if (isArr) {
91106
// Array will always be override
92-
clone = set(clone, path, []);
107+
clone = set(clone, path, finalPrepareArray(originValue, value));
93108
} else if (!originValue || typeof originValue !== 'object') {
94109
// Init container if not exist
95110
clone = set(clone, path, createEmpty(value));
@@ -109,3 +124,10 @@ export function merge<T extends object>(...sources: T[]) {
109124

110125
return clone;
111126
}
127+
128+
/**
129+
* Merge objects which will create
130+
*/
131+
export function merge<T extends object>(...sources: T[]) {
132+
return deepMerge(sources);
133+
}

tests/utils.test.ts

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import pickAttrs from '../src/pickAttrs';
22
import get from '../src/utils/get';
3-
import set, { merge } from '../src/utils/set';
3+
import set, { deepMerge, merge } from '../src/utils/set';
44

55
describe('utils', () => {
66
it('get', () => {
@@ -252,6 +252,39 @@ describe('utils', () => {
252252
[symbol]: 1,
253253
});
254254
});
255+
256+
it('deepMerge for custom logic', () => {
257+
const src = {
258+
rest: 233,
259+
list: [
260+
{
261+
a: 1,
262+
},
263+
],
264+
};
265+
const tgt = {
266+
list: [
267+
{
268+
b: 1,
269+
},
270+
],
271+
};
272+
273+
const merged = deepMerge<any>([src, tgt], {
274+
prepareArray: srcVal => {
275+
return [...(srcVal || [])];
276+
},
277+
});
278+
expect(merged).toEqual({
279+
rest: 233,
280+
list: [
281+
{
282+
a: 1,
283+
b: 1,
284+
},
285+
],
286+
});
287+
});
255288
});
256289
});
257290

0 commit comments

Comments
 (0)