es-toolkit icon indicating copy to clipboard operation
es-toolkit copied to clipboard

`mergeWith` (non-`compat`) dangerously shallow-copies default-mergeable source members

Open rwe opened this issue 3 months ago • 2 comments

PR #556 addressed an issue regarding how merge handles inconsistent source and target types by default.

Looks like this should be applied to mergeWith as well, which still has identical logic to merge before that PR: https://github.com/toss/es-toolkit/blob/f1c7f923b1315bb05cb3a5e4070e6fa50d3127c5/src/object/mergeWith.ts#L74-L78

rwe avatar Sep 06 '25 21:09 rwe

Note that as a consequence of this, by default mergeWith currently results with shallow copies of internal members, making typical usage unsafe. For example:

import assert from 'assert';
import { mergeWith, noop } from 'es-toolkit';

const a = { x: { name: 'a.x' } };
const b = { y: { name: 'b.y' } };
const c = { y: { name: 'c.y' } };

// Appears safe, should be equivalent to default merge!
const m = [a, b, c].reduce((t, s) => mergeWith(t, s, noop), {});

assert.strictEqual(a.x.name, 'a.x');
assert.strictEqual(b.y.name, 'b.y'); // FAIL: source object b.y was mutated!
assert.strictEqual(c.y.name, 'c.y');

rwe avatar Sep 06 '25 21:09 rwe

@raon0211 This issue appears to have been resolved by PR #1495.

Seol-JY avatar Nov 21 '25 18:11 Seol-JY

Thanks @Seol-JY !

raon0211 avatar Dec 07 '25 08:12 raon0211