I know this is a bit of an old issue but the easiest solution in ES2015/ES6 I could come up with was actually quite simple, using Object.assign(),
Hopefully this helps:
/**
* Simple object check.
* @param item
* @returns {boolean}
*/
export function isObject(item) {
return (item && typeof item === 'object' && !Array.isArray(item));
}
/**
* Deep merge two objects.
* @param target
* @param ...sources
*/
export function mergeDeep(target, ...sources) {
if (!sources.length) return target;
const source = sources.shift();
if (isObject(target) && isObject(source)) {
for (const key in source) {
if (isObject(source[key])) {
if (!target[key]) Object.assign(target, { [key]: {} });
mergeDeep(target[key], source[key]);
} else {
Object.assign(target, { [key]: source[key] });
}
}
}
return mergeDeep(target, ...sources);
}
Example usage:
mergeDeep(this, { a: { b: { c: 123 } } });
// or
const merged = mergeDeep({a: 1}, { b : { c: { d: { e: 12345}}}});
console.dir(merged); // { a: 1, b: { c: { d: [Object] } } }
You'll find an immutable version of this in the answer below.
Note that this will lead to infinite recursion on circular references. There's some great answers on here on how to detect circular references if you think you'd face this issue.
Answer from Salakar on Stack Overflowjavascript - How to deep merge instead of shallow merge?
Help with typing a deep merge function.
How to combine object properties in typescript? - Stack Overflow
Deep Merging Utility Types
I know this is a bit of an old issue but the easiest solution in ES2015/ES6 I could come up with was actually quite simple, using Object.assign(),
Hopefully this helps:
/**
* Simple object check.
* @param item
* @returns {boolean}
*/
export function isObject(item) {
return (item && typeof item === 'object' && !Array.isArray(item));
}
/**
* Deep merge two objects.
* @param target
* @param ...sources
*/
export function mergeDeep(target, ...sources) {
if (!sources.length) return target;
const source = sources.shift();
if (isObject(target) && isObject(source)) {
for (const key in source) {
if (isObject(source[key])) {
if (!target[key]) Object.assign(target, { [key]: {} });
mergeDeep(target[key], source[key]);
} else {
Object.assign(target, { [key]: source[key] });
}
}
}
return mergeDeep(target, ...sources);
}
Example usage:
mergeDeep(this, { a: { b: { c: 123 } } });
// or
const merged = mergeDeep({a: 1}, { b : { c: { d: { e: 12345}}}});
console.dir(merged); // { a: 1, b: { c: { d: [Object] } } }
You'll find an immutable version of this in the answer below.
Note that this will lead to infinite recursion on circular references. There's some great answers on here on how to detect circular references if you think you'd face this issue.
You can use Lodash merge:
var object = {
'a': [{ 'b': 2 }, { 'd': 4 }]
};
var other = {
'a': [{ 'c': 3 }, { 'e': 5 }]
};
console.log(_.merge(object, other));
// => { 'a': [{ 'b': 2, 'c': 3 }, { 'd': 4, 'e': 5 }] }
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>
Hey all, I'm wondering if there are any smart people out there looking a little bit of a challenge. On the surface this didn't seem like it would be very hard when I started but it's been a lot more difficult than I expected.
But anyway, essentially I'm trying to type 2 functions. One that will deeply merge any 2 given objects into a new resulting object. And the other that will deeply merge an array of 2+ objects into a new resulting object.
I feel I'm close to getting the typings all correct but I'm having trouble with the second of the 2 functions. I'd really appreciate any help with solving this issue. I'd also really love if anyone was able to peer review my current PR.
https://github.com/TehShrike/deepmerge/pull/211
Thanks for reading :)
ยป npm install ts-deepmerge
Seems like this should do the trick:
var objectA = {
propertyA: 1,
propertyB: 2,
.
. // more properties here
.
propertyM: 13
};
var objectB = {
propertyN: 14,
propertyO: 15,
.
. // more properties here
.
propertyZ: 26
};
var objectC = {...objectA, ...objectB}; // this is the answer
var a = objectC.propertyA;
var n = objectC.propertyN;
Based on this article: https://blog.mariusschulz.com/2016/12/23/typescript-2-1-object-rest-and-spread
In addition, the order of the variables in the decomposition matters. Consider the following:
var objectA = {
propertyA: 1,
propertyB: 2, // same property exists in objectB
propertyC: 3
};
var objectB = {
propertyX: 'a',
propertyB: 'b', // same property exists in objectA
propertyZ: 'c'
};
// objectB will override existing properties, with the same name,
// from the decomposition of objectA
var objectC = {...objectA, ...objectB};
// result: 'b'
console.log(objectC.propertyB);
// objectA will override existing properties, with the same name,
// from the decomposition of objectB
var objectD = {...objectB, ...objectA};
// result: '2'
console.log(objectD.propertyB);
(Is there an operator that can extract the interface/type of an existing object? Is it possible?)
You should go for typeof.
type typeA = typeof objectA;
type typeB = typeof objectB;
To get them merged you can use intersection operation as basarat already pointed out.
type typeC = typeA & typeB
ยป npm install object-deep-merge
ยป npm install deepmerge