diff --git a/src/utils/set.ts b/src/utils/set.ts index 7d465a56..e48ffe55 100644 --- a/src/utils/set.ts +++ b/src/utils/set.ts @@ -25,7 +25,12 @@ function internalSet( // Delete prop if `removeIfUndefined` and value is undefined if (removeIfUndefined && value === undefined && restPath.length === 1) { - delete clone[path][restPath[0]]; + const origin = clone[path]; + if (origin && typeof origin === 'object') { + const child = Array.isArray(origin) ? [...origin] : { ...origin }; + delete child[restPath[0]]; + clone[path] = child; + } } else { clone[path] = internalSet(clone[path], restPath, value, removeIfUndefined); } diff --git a/tests/utils.test.ts b/tests/utils.test.ts index f0d4385f..248cb8f0 100644 --- a/tests/utils.test.ts +++ b/tests/utils.test.ts @@ -59,14 +59,12 @@ describe('utils', () => { expect(set({}, ['notExist'], undefined, true)).toEqual({}); // Delete value - const target = set( - { keep: { light: 2333 } }, - ['keep', 'light'], - undefined, - true, - ); - expect(target).toEqual({ keep: {} }); + const source = { keep: { light: 2333, bamboo: 1 } }; + const target = set(source, ['keep', 'light'], undefined, true); + expect(target).toEqual({ keep: { bamboo: 1 } }); expect('light' in target.keep).toBeFalsy(); + expect(source).toEqual({ keep: { light: 2333, bamboo: 1 } }); + expect(target.keep).not.toBe(source.keep); // Mid path not exist const midTgt = set( @@ -99,6 +97,16 @@ describe('utils', () => { expect('lv4' in longTgt.lv1.lv2.lv3).toBeFalsy(); }); + it.each(['str', 123, true, Symbol('value'), BigInt(1)])( + 'preserves a primitive parent when removing a missing property: %s', + value => { + const source = { keep: value }; + const target = set(source, ['keep', 'light'], undefined, true); + expect(target.keep).toBe(value); + expect(source.keep).toBe(value); + }, + ); + describe('merge', () => { it('basic', () => { const merged = merge({}, { a: 1 }, { b: 2 });