Created
January 20, 2022 23:14
-
-
Save kendallroth/1f5afca32334dc395933c921ddd1fbe9 to your computer and use it in GitHub Desktop.
Update value in nested objects (with/without mutation)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Dynamically sets a deeply nested value in an object (returns new object) | |
* | |
* NOTE: By default it will create any missing nested keys! | |
* | |
* @param obj - Object which contains the value to set | |
* @param path - Path to nested key being set | |
* @param value - Target value to set | |
* @param recursive - Whether to create non-existing paths | |
* @returns Updated nested object | |
*/ | |
const setDeep = ( | |
obj: Record<string, any> = {}, | |
[first, ...rest]: string[], | |
value: any, | |
recursive = true, | |
): Record<string, any> => { | |
// Optional prevent creating recursive keys if path is invalid/missing | |
if (!recursive && typeof obj[first] === "undefined") return obj; | |
// Arrays are currently not supported (will ignore) | |
if (Array.isArray(obj[first])) return obj; | |
return { | |
...obj, | |
[first]: rest.length ? setDeep(obj[first], rest, value, recursive) : value, | |
}; | |
}; | |
/** | |
* Dynamically sets a deeply nested value in an object (mutates input). | |
* | |
* By default it will create any missing nested keys! | |
* | |
* @param obj - Object which contains the value to set | |
* @param path - Path to nested key being set | |
* @param value - Target value to set | |
* @param recursive - Whether to create non-existing paths | |
*/ | |
const mutateDeep = ( | |
obj: Record<string, any>, | |
path: string[], | |
value: any, | |
recursive = true, | |
): void => { | |
let subObject = obj; | |
path.forEach((key, idx) => { | |
// Subobject will only be undefined when previous key did not exist | |
// and was not created (non-recursive call). | |
if (!subObject) return; | |
const isLastKey = idx === path.length - 1; | |
const isDefined = typeof subObject[key] !== "undefined"; | |
if (isLastKey) { | |
subObject[key] = value; | |
} else if (!isDefined && recursive) { | |
subObject[key] = {}; | |
} | |
subObject = subObject[key]; | |
}); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment