Skip to content

Instantly share code, notes, and snippets.

@supasympa
Last active April 17, 2019 22:37
Show Gist options
  • Save supasympa/22f3421013582f7024486bdfcba79eef to your computer and use it in GitHub Desktop.
Save supasympa/22f3421013582f7024486bdfcba79eef to your computer and use it in GitHub Desktop.
A cheap deep merge
const { keys } = Object;
const isObject = a => typeof a === "object" && !Array.isArray(a);
const bothObjects = (a, b) => isObject(a) && isObject(b);
const neitherObjects = (a, b) => !isObject(a) && !isObject(b);
const sameType = (a, b) => (typeof a === typeof b);
const merge = (a, b) =>
bothObjects(a, b)?
deepMerge(a, b):
isObject(a) && !isObject(b)?
a:
b;
// swap merge for concatenation / summation with this:
const addOrMerge = (a, b) =>
neitherObjects(a, b) && sameType(a, b)?
(a + b):
merge(a,b);
const coalesceByKey = source => (acc, key) =>
(acc[key] && source[key]
? (acc[key] = merge(acc[key], source[key]))
: (acc[key] = source[key])) && acc;
/**
* Merge all sources into the target
* overwriting primitive values in the the accumulated target as we go (if they already exist)
* @param {*} target
* @param {...any} sources
*/
const deepMerge = (target, ...sources) =>
sources.reduce(
(acc, source) => keys(source).reduce(coalesceByKey(source), acc),
target
);
console.log(deepMerge({ a: 1 }, { a: 2 }));
console.log(deepMerge({ a: 1 }, { a: { b: 2 } }));
console.log(deepMerge({ a: { b: 2 } }, { a: 1 }));
console.log(
deepMerge(
{ a: 1, d: ["foo"] },
{ d: { dd: 99 } },
{ c: 3, d: { e: 4 } },
{ f: 100, g: ["bar"] }
)
);
console.log(
deepMerge(
{ name: "simple" },
{
name: "complex",
index: 1,
type: "complex",
subType: {
name: "sub",
index: 2,
type: "simple",
subSubType: {
name: "sub-sub",
age: 3,
type: "simple"
}
}
},
{
name: "complex",
index: 4,
type: "complex",
subType: {
name: "sub",
index: 5,
type: "simple"
}
}
)
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment