Skip to content

Instantly share code, notes, and snippets.

@th3terrorist
Last active October 9, 2023 10:21
Show Gist options
  • Save th3terrorist/1d72fb10c7b2a1ddaa6283212f14738d to your computer and use it in GitHub Desktop.
Save th3terrorist/1d72fb10c7b2a1ddaa6283212f14738d to your computer and use it in GitHub Desktop.
Deeply merge js objects
/**
* Merges two arrays by concatenating their elements uniquely using `new Set(...)`.
*
* @param {Array} a1 - The first array to merge.
* @param {Array} a2 - The second array to merge.
* @returns {Array} A new array containing elements from both input arrays.
*/
const mergeArray = (a1, a2) => Array.from(new Set([...a1, ...a2]))
/**
* Recursively merges two objects based on their types and structure.
*
* @param {*} o1 - The first object to merge.
* @param {*} o2 - The second object to merge.
* @returns {*} A new object that is a merge of the two input objects.
* @throws {Error} Throws an error if either input is not an object.
*/
const merge = (o1, o2) => {
if (typeof o1 === 'undefined') return o2
if (typeof o1 !== typeof o2) return undefined
if (Array.isArray(o1) && Array.isArray(o2)) return mergeArray(o1, o2)
// They're some other type, prioritize the second object as there is no merge strategy
if (typeof o1 !== 'object') return o2
return Object.keys(o2).reduce((acc, k) => {
const result = merge(o1[k], o2[k])
return result ? { ...acc, [k]: result } : acc
}, o1)
}
/**
* Deeply merges two objects by recursively combining their properties.
*
* @param {Object} o1 - The first object to merge.
* @param {Object} o2 - The second object to merge.
* @returns {Object} A new object that is a deep merge of the two input objects.
* @throws {Error} Throws an error if either input is not an object.
*/
const deepMerge = (o1, o2) => {
if (typeof o1 !== 'object')
throw new Error(`First argument should an object got: ${typeof o1}`)
if (typeof o2 !== 'object')
throw new Error(`Second argument should an object got: ${typeof o2}`)
return merge(o1, o2)
}
/**
* Deeply merges an array of objects into a single object, applying a recursive merge operation.
*
* @param {Array} arr - An array of objects to merge.
* @returns {Object} A new object that is a deep merge of all objects in the input array.
* @throws {Error} Throws an error if any element in the array is not an object.
*/
const deepMergeAll = (...[head, ...tail]) =>
tail?.length ? tail.reduce((acc, o) => deepMerge(acc, o), head) : head
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment