Set object value at the string path

Given an object, a path in the string or array of strings format, and a value, update the value at the given path in the object.

This is a polyfill for lodash._set() method and is opposite of lodash._get() method.


const object = { 'a': [{ 'b': { 'c': 3 } }] };

set(object, 'a[0].b.c', 4);
// 4
set(object, ['x', '0', 'y', 'z'], 5);
// 5

To implement this function, we will first check if the provided path is a string or an array of strings.

If it is string then filter all the special characters like [, ] and split the string on . to get all the path keys in an array.

Then using a helper function we can assign the value to the provided path.

  • Get only the first key from the path array and aggregate the rest of the keys.
  • If there are no more keys left to update, assign the value to the current key.
  • Else recursively call the same function with the current value for the next path.
  • While moving to the next path, check the type of key, if it is numeric the value should be an array thus pass array, else if it is a string pass the object.

Note:- This will override the existing value and assign a new one.

const helper = (obj, path, value) => {
    // get the current and the remaining keys from the path
    let [current,] =  path;
    // if there are more keys
    // add the value as an object or array
    // depending upon the typeof key
    if(rest.length > 0){
        // if there is no key present
        // create a new one
          // if the key is numeric
          // add an array
          // else add an object
          const isNumber = `${+rest[0]}` === rest[0];
          obj[current] = isNumber ? [] : {};
        // recurisvely update the remaining path
        // if the last path is not of object type
        // but key is then
        // create an object or array based on the key
        // and update the value
        if(typeof obj[current] !== 'object'){
          // determine if the key is string or numeric 
          const isNumber = `${+rest[0]}` === rest[0];
          obj[current] = helper(isNumber ? [] : {}, rest, value)
        // else directly update value
          obj[current] = helper(obj[current], rest, value);
    // else directly assing the value to the key
      obj[current] = value;
    // return the updated obj
    return obj;

const set = (obj, path, value) => {
   let pathArr = path;
   // if path is of string type
   // replace the special characters
   // and split the string on . to get the path keys array
   if(typeof path === 'string'){
     pathArr = path.replace('[', '.').replace(']', '').split(".");
   // use the helper function to update
   helper(obj, pathArr, value);
const abc = {
  a: {
    b: {
      c: [1, 2, 3]
    d: {
      a: "hello"

const instance1 = JSON.parse(JSON.stringify(abc));
set(instance1, 'a.b.c', 'learnersbucket');

const instance2 = JSON.parse(JSON.stringify(abc));
set(instance2, 'a.b.c.0', 'learnersbucket');

const instance3 = JSON.parse(JSON.stringify(abc));
set(instance3, 'a.b.c[1]', 'learnersbucket');

const instance4 = JSON.parse(JSON.stringify(abc));
set(instance4, ['a', 'b', 'c', '2'], 'learnersbucket');

const instance5 = JSON.parse(JSON.stringify(abc));
set(instance5, 'a.b.c[3]', 'learnersbucket');

const instance6 = JSON.parse(JSON.stringify(abc));
set(instance6, 'a.c.d[0]', 'learnersbucket');
// valid digits treated as array elements

const instance7 = JSON.parse(JSON.stringify(abc));
set(instance7, 'a.d.01', 'learnersbucket');
// invalid digits treated as property string

const object = { 'a': [{ 'b': { 'c': 3 } }] };
set(object, 'a[0].b.c', 4);

set(object, ['x', '0', 'y', 'z'], 5);