From f888cf30847a5dc0afc586a9b217f17f9ede2b33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E8=B4=A7=E7=88=B1=E5=90=83=E7=99=BD=E8=90=9D?= =?UTF-8?q?=E5=8D=9C?= Date: Mon, 8 Dec 2025 17:00:18 +0800 Subject: [PATCH 1/2] feat: support custom merge (#711) * feat: support deep merge * chore: adjust * chore: adjust * chore: adjust * chore: rename * chore: rename --- src/index.ts | 2 +- src/utils/set.ts | 29 ++++++++++++++++++++++++++--- tests/utils.test.ts | 35 ++++++++++++++++++++++++++++++++++- 3 files changed, 61 insertions(+), 5 deletions(-) diff --git a/src/index.ts b/src/index.ts index 84097aa4..166d66d7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -3,7 +3,7 @@ export { default as useMergedState } from './hooks/useMergedState'; export { default as useControlledState } from './hooks/useControlledState'; export { supportNodeRef, supportRef, useComposeRef } from './ref'; export { default as get } from './utils/get'; -export { default as set, merge } from './utils/set'; +export { default as set, merge, mergeWith } from './utils/set'; export { default as warning, noteOnce } from './warning'; export { default as omit } from './omit'; export { default as toArray } from './Children/toArray'; diff --git a/src/utils/set.ts b/src/utils/set.ts index 39ddac39..c0db65d5 100644 --- a/src/utils/set.ts +++ b/src/utils/set.ts @@ -66,10 +66,25 @@ function createEmpty(source: T) { const keys = typeof Reflect === 'undefined' ? Object.keys : Reflect.ownKeys; +// ================================ Merge ================================ +export type MergeFn = (current: any, next: any) => any; + /** - * Merge objects which will create + * Merge multiple objects. Support custom merge logic. + * @param sources object sources + * @param config.prepareArray Customize array prepare function. + * It will return empty [] by default. + * So when match array, it will auto be override with next array in sources. */ -export function merge(...sources: T[]) { +export function mergeWith( + sources: T[], + config: { + prepareArray?: MergeFn; + } = {}, +) { + const { prepareArray } = config; + const finalPrepareArray: MergeFn = prepareArray || (() => []); + let clone = createEmpty(sources[0]); sources.forEach(src => { @@ -89,7 +104,7 @@ export function merge(...sources: T[]) { if (isArr) { // Array will always be override - clone = set(clone, path, []); + clone = set(clone, path, finalPrepareArray(originValue, value)); } else if (!originValue || typeof originValue !== 'object') { // Init container if not exist clone = set(clone, path, createEmpty(value)); @@ -109,3 +124,11 @@ export function merge(...sources: T[]) { return clone; } + +/** + * Merge multiple objects into a new single object. + * Arrays will be replaced by default. + */ +export function merge(...sources: T[]) { + return mergeWith(sources); +} diff --git a/tests/utils.test.ts b/tests/utils.test.ts index dc0f439d..580c303c 100644 --- a/tests/utils.test.ts +++ b/tests/utils.test.ts @@ -1,6 +1,6 @@ import pickAttrs from '../src/pickAttrs'; import get from '../src/utils/get'; -import set, { merge } from '../src/utils/set'; +import set, { mergeWith, merge } from '../src/utils/set'; describe('utils', () => { it('get', () => { @@ -252,6 +252,39 @@ describe('utils', () => { [symbol]: 1, }); }); + + it('customMerge for custom logic', () => { + const src = { + rest: 233, + list: [ + { + a: 1, + }, + ], + }; + const tgt = { + list: [ + { + b: 1, + }, + ], + }; + + const merged = mergeWith([src, tgt], { + prepareArray: current => { + return [...(current || [])]; + }, + }); + expect(merged).toEqual({ + rest: 233, + list: [ + { + a: 1, + b: 1, + }, + ], + }); + }); }); }); From 8ea0ed113cf33e4670aaa4e4622d4139ad8e406b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E8=B4=A7=E6=9C=BA=E5=99=A8=E4=BA=BA?= Date: Mon, 8 Dec 2025 17:10:49 +0800 Subject: [PATCH 2/2] chore: bump version to 1.5.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3cf7898f..d492a68d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@rc-component/util", - "version": "1.4.0", + "version": "1.5.0", "description": "Common Utils For React Component", "keywords": [ "react",