mergeWith()
mergeWith<
T,U>(object,source,customizer):T&U
Recursively merges objects using a customizer function to resolve conflicts.
If customizer returns undefined, merging is handled by the default strategy.
Type Parametersโ
T: T extends Record<string, unknown>โ
The type of the target object.
U: U extends Record<string, unknown>โ
The type of the source object.
Parametersโ
object: Tโ
The destination object.
source: Uโ
The source object.
customizer: (objValue, srcValue, key, object, source) => unknownโ
The function to customize assigned values.
Returns: T & Uโ
A new deeply merged object.
Sinceโ
2.0.0
Noteโ
Arrays are replaced by default unless customizer handles them.
Performanceโ
O(n) where n is total number of properties.
Also known asโ
mergeDeepWith (Ramda) ยท mergeWith (Lodash, es-toolkit) ยท โ (Remeda, Radashi, Effect, Modern Dash, Antfu)
Exampleโ
// Concatenate arrays instead of replacing
mergeWith(
{ items: [1, 2] },
{ items: [3, 4] },
(objValue, srcValue) => {
if (Array.isArray(objValue) && Array.isArray(srcValue)) {
return objValue.concat(srcValue);
}
return undefined; // Use default merge
}
);
// => { items: [1, 2, 3, 4] }
// Sum numeric values
mergeWith(
{ a: 1, b: 2 },
{ a: 3, b: 4 },
(objValue, srcValue) => {
if (typeof objValue === 'number' && typeof srcValue === 'number') {
return objValue + srcValue;
}
return undefined;
}
);
// => { a: 4, b: 6 }
How it works?โ
Recursively merges objects using a customizer to resolve conflicts.
Array Concatenationโ
Sum Valuesโ
mergeDeep vs mergeWithโ
| mergeDeep | mergeWith | |
|---|---|---|
| Customization | None | Full control |
| Arrays | Replace | Customizable |
| Conflicts | Left/Right wins | Custom logic |
Use Casesโ
Custom Array Merging strategies ๐โ
Merge objects with custom array handling. Essential for flexible data merging.
import { mergeWith } from "pithos/arkhe/object/merge-with";
const baseConfig = {
plugins: ["plugin-a", "plugin-b"],
rules: { semi: "error" },
};
const extendedConfig = {
plugins: ["plugin-c"],
rules: { quotes: "warn" },
};
// Concatenate arrays instead of replacing
const merged = mergeWith(baseConfig, extendedConfig, (objValue, srcValue) => {
if (Array.isArray(objValue) && Array.isArray(srcValue)) {
return [...objValue, ...srcValue];
}
return undefined; // Use default merge for non-arrays
});
console.log(merged);
// { plugins: ["plugin-a", "plugin-b", "plugin-c"], rules: { semi: "error", quotes: "warn" } }
Numeric Value Accumulation ๐โ
Accumulate numeric values during merge. Critical for aggregating statistics.
import { mergeWith } from "pithos/arkhe/object/merge-with";
const week1Stats = {
visits: 1000,
clicks: 150,
conversions: 25,
};
const week2Stats = {
visits: 1200,
clicks: 180,
conversions: 30,
};
// Sum numeric values
const totalStats = mergeWith(week1Stats, week2Stats, (objValue, srcValue) => {
if (typeof objValue === "number" && typeof srcValue === "number") {
return objValue + srcValue;
}
return undefined;
});
console.log(totalStats);
// { visits: 2200, clicks: 330, conversions: 55 }
Conditional Overwrite logicโ
Apply conditional rules when merging values. Important for complex merge scenarios.
import { mergeWith } from "pithos/arkhe/object/merge-with";
const defaultSettings = {
timeout: 30000,
retries: 3,
cache: { enabled: true, ttl: 3600 },
};
const userSettings = {
timeout: -1, // Invalid value
retries: 5,
cache: { enabled: false, ttl: 0 }, // 0 is invalid for ttl
};
// Only accept valid values
const validatedSettings = mergeWith(defaultSettings, userSettings, (objValue, srcValue, key) => {
// Reject negative timeouts
if (key === "timeout" && typeof srcValue === "number" && srcValue < 0) {
return objValue;
}
// Reject zero TTL
if (key === "ttl" && srcValue === 0) {
return objValue;
}
return undefined; // Use default merge
});
console.log(validatedSettings);
// { timeout: 30000, retries: 5, cache: { enabled: false, ttl: 3600 } }