refactor(Table): prefer Object.assign where applicable#12218
Conversation
`mergeWith` is called without a third function argument making it a plain `merge` which can be implemented with `Object.assign` as this function should always receive objects.
WalkthroughThe Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~8 minutes 🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Preview: https://pf-react-pr-12218.surge.sh A11y report: https://pf-react-pr-12218-a11y.surge.sh |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@packages/react-table/src/components/Table/base/merge-props.ts`:
- Around line 15-23: The shallow clone via Object.assign({}, props[0]) still
shares nested references so mergeWith mutates props[0]; keep the early-return
for the single-prop case (return a shallow clone of props[0]) but when merging
multiple props call mergeWith with an empty object as the target (e.g.
mergeWith({}, props[0], ...restProps, customizer)) so the merge operates on a
fresh object and never mutates nested objects in props[0]; adjust references to
firstProps/mergeWith in merge-props.ts accordingly.
| const firstProps = Object.assign({}, props[0]); | ||
| const restProps = props.slice(1); | ||
|
|
||
| if (!restProps.length) { | ||
| return mergeWith({}, firstProps); | ||
| return firstProps; | ||
| } | ||
|
|
||
| // Avoid mutating the first prop collection | ||
| return mergeWith(mergeWith({}, firstProps), ...restProps, (a: any, b: any, key: any) => { | ||
| return mergeWith(firstProps, ...restProps, (a: any, b: any, key: any) => { |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
lodash mergeWith mutate target object nested deep merge behavior
💡 Result:
- Yes—
_.mergeWithmutates the first argument (object). It returns that same object after merging. [1][2] - It performs a deep (recursive) merge of nested plain objects, similar to
_.merge; sources are applied left→right and later sources win on conflicts. [2][3] - Arrays are merged recursively by index by default (not concatenated). Example behavior: merging
[{b:2},{d:4}]with[{c:3},{e:5}]produces[{b:2,c:3},{d:4,e:5}]. [3] customizercontrols how values merge: it’s called with(objValue, srcValue, key, object, source, stack); if it returnsundefined, Lodash falls back to default merge behavior. [1][2]- Common pattern: concatenate arrays by returning
objValue.concat(srcValue)whenobjValueis an array. [1]
- Common pattern: concatenate arrays by returning
To avoid mutating an existing target, merge into a fresh object, e.g. _.mergeWith({}, target, source, customizer) (or clone first). [1][2]
Sources:
[1] Lodash mergeWith docs (note on mutation + customizer + array concat example)
[2] Lodash official docs excerpt (mergeWith signature + “mutates object”)
[3] Lodash merge docs (deep merge rules + array/object recursive merge example)
🏁 Script executed:
cat -n packages/react-table/src/components/Table/base/merge-props.tsRepository: patternfly/patternfly-react
Length of output: 1490
Replace shallow clone with empty merge target to prevent nested mutation.
Object.assign is shallow, so nested objects in firstProps remain references to props[0]. When mergeWith then mutates firstProps recursively, it mutates the original nested objects in props[0], contradicting the "Avoid mutating the first prop collection" intent. Merge into an empty object instead to fully isolate the result.
🔧 Proposed fix
- const firstProps = Object.assign({}, props[0]);
+ const firstProps = props[0];
const restProps = props.slice(1);
if (!restProps.length) {
- return firstProps;
+ return Object.assign({}, firstProps);
}
// Avoid mutating the first prop collection
- return mergeWith(firstProps, ...restProps, (a: any, b: any, key: any) => {
+ return mergeWith({}, firstProps, ...restProps, (a: any, b: any, key: any) => {🤖 Prompt for AI Agents
In `@packages/react-table/src/components/Table/base/merge-props.ts` around lines
15 - 23, The shallow clone via Object.assign({}, props[0]) still shares nested
references so mergeWith mutates props[0]; keep the early-return for the
single-prop case (return a shallow clone of props[0]) but when merging multiple
props call mergeWith with an empty object as the target (e.g. mergeWith({},
props[0], ...restProps, customizer)) so the merge operates on a fresh object and
never mutates nested objects in props[0]; adjust references to
firstProps/mergeWith in merge-props.ts accordingly.
|
The AI bot is right, Object.assign only does a shallow clone so this wouldn't be the same. |
|
An alternative might be windows.structuredClone() which is baseline. |
mergeWithis called without a third function argument making it a plainmergewhich can be implemented withObject.assignas this function should always receive objects.What: Closes #
Additional issues:
Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.