Merge nested plain objects deeply
JavaScript
// Deep merge plain objects into a new value; arrays are replaced, not merged.
function isPlainObject(value) {
if (value === null || typeof value !== 'object') return false;
const proto = Object.getPrototypeOf(value);
return proto === Object.prototype || proto === null;
}
function deepMerge(...sources) {
const result = {};
for (const source of sources) {
if (!isPlainObject(source)) continue;
for (const [key, value] of Object.entries(source)) {
const current = result[key];
result[key] = isPlainObject(current) && isPlainObject(value)
? deepMerge(current, value)
: isPlainObject(value) ? deepMerge({}, value) : value;
}
}
return result;
}
const defaults = { retries: 2, headers: { accept: 'json' }, tags: ['a'] };
const custom = { headers: { 'x-trace': 'on' }, tags: ['b'] };
console.log(deepMerge(defaults, custom));
// { retries: 2, headers: { accept: 'json', 'x-trace': 'on' }, tags: ['b'] }