This is an alternative to lodash.merge.
type Props = Record<string, any>
const deepMerge = (target: Props, ...sources: Props[]): Props => {
if (!sources.length) {
return target
}
Object.entries(sources.shift() ?? []).forEach(([key, value]) => {
if (value) {
if (!target[key]) {
Object.assign(target, { [key]: {} })
}
if (
value.constructor === Object ||
(value.constructor === Array &&
value.find(v => v.constructor === Object))
) {
deepMerge(target[key], value)
} else if (value.constructor === Array) {
Object.assign(target, {
[key]: value.find(v => v.constructor === Array)
? target[key].concat(value)
: [...new Set([...target[key], ...value])],
})
} else {
Object.assign(target, { [key]: value })
}
}
})
return target
}
deepMerge(
{
a: '__PROPERTY_A__',
b: '__PROPERTY_B__',
},
{
c: '__PROPERTY_C__',
}
)
// Returns
{
a: '__PROPERTY_A__',
b: '__PROPERTY_B__',
c: '__PROPERTY_C__',
}
deepMerge(
{
a: '__PROPERTY_A__',
b: '__PROPERTY_B__',
},
{
b: '__PROPERTY_B__',
c: '__PROPERTY_C__',
}
)
// Returns
{
a: '__PROPERTY_A__',
b: '__PROPERTY_B__',
c: '__PROPERTY_C__',
}
deepMerge(
{
items: ['h', 'b'],
},
{
items: ['a', 'b'],
}
)
// Returns
{
items: ['h', 'b', 'a'],
}
deepMerge(
{
items: [
[1, 2, 3],
[4, 5, 6],
],
},
{
items: [[4, 5, 6, 7, 8]],
}
)
// Returns
{
items: [
[1, 2, 3],
[4, 5, 6],
[4, 5, 6, 7, 8],
],
}
deepMerge(
{
name: '__NAME__',
orders: [
{
orderId: 12345,
item: 'Silk gloves',
},
{
orderId: 67891,
item: 'Black jeans',
},
],
},
{
orders: [
{
orderId: 12345,
item: 'Silk gloves',
price: 99.99,
},
],
}
)
// Returns
{
name: '__NAME__',
orders: [
{
item: 'Silk gloves',
orderId: 12345,
price: 99.99,
},
{
item: 'Black jeans',
orderId: 67891,
},
],
}
deepMerge(
{
version: 1,
a: '__PROPERTY_A__',
b: {
a: '__PROPERTY_A__',
},
c: {
a: '__PROPERTY_A__',
e: '__PROPERTY_E__',
},
},
{
nested: true,
date: new Date('2021-05-05').toISOString(),
a: '__PROPERTY_A__',
b: {
b: '__PROPERTY_B__',
},
c: {
b: '__PROPERTY_B__',
d: '__PROPERTY_D__',
f: {
a: '__PROPERTY_A__',
b: '__PROPERTY_B__',
c: '__PROPERTY_C__',
d: {
a: '__PROPERTY_A__',
},
},
},
}
)
// Returns
{
nested: true,
version: 1,
date: '2021-05-05T00:00:00.000Z',
a: '__PROPERTY_A__',
b: {
a: '__PROPERTY_A__',
b: '__PROPERTY_B__',
},
c: {
a: '__PROPERTY_A__',
b: '__PROPERTY_B__',
d: '__PROPERTY_D__',
e: '__PROPERTY_E__',
f: {
a: '__PROPERTY_A__',
b: '__PROPERTY_B__',
c: '__PROPERTY_C__',
d: {
a: '__PROPERTY_A__',
},
},
},
}