Search code examples
reactjstypescriptreact-state-management

ReactJs - TypeError: Cannot assign to read only property 'name' of object '#<Object>'


I have an array of objects:

var subcategories = [{name:'gloves', tag:'wool'}, {name:'boots', tag: 'leather'}]

All I want to do is to find the index of the object to change a name or a tag. I use this function:

function setSubcat(val, index, lang){
   var newArr = []
   var obj = {
      'name': val
   }
   subcategories.map((val, i)=>{
      if(index === i){
         var newObj = Object.assign(val, obj)
         newArr.push(newObj)
      }
      newArr.push(val)
   })
   setSubcategories(newArr)
}
           

The error happens at var newObj = Object.assign(val, obj)

I thought the error means I can't mutate the state directly and so I have to make a copy. I thought that mapping through subcategories and push it into a local newArr means I made a copy of the array. But it wasn't working when I wanted to change a value of object in it so I used Object.assign which I thought would deep copy the particular object from the array, but it's not working either.

What am I missing here?


Solution

  • As pointed in comments:

    • the code you posted does not show how you created object with unmodifiable property
    • you can create a new object and not use Object.assign to get rid of the error
    • use map function in more idiomatic way
    interface TaggedItem {
        name: string,
        tag: string
    }
    var subcategories = [{name:'gloves', tag:'wool'}, {name:'boots', tag: 'leather'}];
    
    function setSubcat(val: string, index: number, _lang: any){
       var obj: Partial<TaggedItem> = {
          'name': val
       }
       var newArr: TaggedItem[] = subcategories.map((val, i)=>{
          if(index === i){
            return {
                ...val,
                ...obj
            } 
          } else {
            return {...val};
            // or return val; if you don't need a full copy
          }
       })
       console.log(newArr);
    }
    
    setSubcat('newName', 0, undefined);
    

    Playground link