I have a library where a default config is defined as an object and assigned to CONFIG. However, a user of the library can pass-in a customized config. We merge these, of course. I ran into a bump along the way, as I discovered that assigned objects create a reference to the object; so when I pass CONFIG into the merge function I need to ensure I don't alter the original CONFIG by way of reference.
This is how I resolved the issue, but wanted some feedback on if there is a better way. I created the deepCopy function for the purposes of documentation - as I'd otherwise have no intuition that I'm 'deep copying' an object using the stringify/parse code.
const deepCopy = (object: {}): any => {
return JSON.parse(JSON.stringify(object))
}
let initial_merge_call = true
export const mergeObjects = ({ current, updates }: { current: KeyStringObjectAny, updates: KeyStringObjectAny }): any => {
if (!current || !updates)
throw new Error("Both 'current' and 'updates' must be passed-in to merge()")
if (typeof current !== 'object' || typeof updates !== 'object')
throw new Error("Both 'current' and 'updates' must be passed-in as objects to merge()")
/**
* We need to make a deep copy of `current`, otherwise we end up altering the original `CONFIG` because
* `current` is a reference to it; but we can't deep copy recursive merges of objects as that would break
* a needed reference to `merged`.
*/
let merged = initial_merge_call ? deepCopy(current) : current
for (let key of Object.keys(updates)) {
if (typeof updates[key] !== 'object') {
merged[key] = updates[key]
} else {
/* key is an object, run merge on it */
initial_merge_call = false
mergeObjects({ current: merged[key], updates: updates[key] })
}
}
initial_merge_call = true
return merged
}