0

I have got a object called curNode like this

{
    "name": "CAMPAIGN",
    "attributes": {},
    "children": []
}

I am trying to push to the object as shown below

curNode!.children!.push({
        name: newNodeName,
        children: [],
});

I get the below error

TypeError: Cannot add property 0, object is not extensible
    at Array.push (<anonymous>)
jeril
  • 1,109
  • 2
  • 17
  • 35
  • 2
    The array is frozen. Either don't freeze it if it's your code, or if it's not then most likely you sholdn't be mutating it. – VLAZ Nov 10 '22 at 11:43
  • Sorry may I know how not to freeze it. FYKI, I am calling curNode.children.push({}) during form submit. I am using formik forms – jeril Nov 10 '22 at 12:18
  • I tried console.log(Object.isExtensible(curNode)) and returns false. Wondering what could be done here. – jeril Nov 10 '22 at 19:35
  • I am using redux. Guess it has something to do with redux. – jeril Nov 10 '22 at 19:47
  • 1
    Don't mutate the object. That's the core philosophy of Redux, is it not? Treat the state as immutable. That's what you should be doing. – VLAZ Nov 10 '22 at 23:30

2 Answers2

0

If you copy curNode to the TS playground, and hover over the type, you'll see its type is:

type T = {
    name: string;
    attributes: {};
    children: never[];
}

You can't add any elements to a never[] array.

In order to make the code work, you can declare a type and use it when you init curNode:

interface TNode {
    name?: string
    attributes?: object,
    children?: TNode[]
}

const curNode : TNode = {
    name: "CAMPAIGN",
    attributes: {},
    children: []
};

const newNodeName = "Foo"

curNode.children?.push({
    name: newNodeName,
    children: []
});

console.log(curNode);

// Output
//[LOG]: {
//  "name": "CAMPAIGN",
//  "attributes": {},
//  "children": [
//    {
//      "name": "Foo",
//      "children": []
//    }
//  ]
//} 

link to TS Playground


Edit:

Another option is to use new Array<any> instead of [] when initializing the array:

const curNode = {
    name: "CAMPAIGN",
    attributes: {},
    children: new Array<any>
};

const newNodeName = "Foo"

curNode.children?.push({
    name: newNodeName,
    children: []
});

console.log(curNode);
Behrang
  • 46,888
  • 25
  • 118
  • 160
  • "*You can't add any elements to a never[] array.*" **this is not what the error means**! The error is *runtime* because the array is *immutable* thus attempting to push results in TypeError. [Demo](https://jsbin.com/pupomacojo/edit?js,console). Open it in chrome to see the exact same message as in the question. FF will give a different one with the same meaning. You cannot mutate the frozen object. It is absolutely ***not*** a compiler error from TS. The only *correct* type change is to declare the objects as readonly to get compiler errors when trying to mutate them. – VLAZ Nov 10 '22 at 23:26
  • TypeScript infers the type of children as `never[]` and the compiler fails with an error if you try to push anything into an array of type `never`. Example [here](https://www.typescriptlang.org/play?#code/MYewdgzgLgBAnjAvDA3gKBpmBDAXDAbQF00BfNNOAOmyoAcBXCACwAoBGASiA). See also: [why-does-typescript-resolve-to-never](https://stackoverflow.com/questions/74389591/why-does-typescript-resolve-to-never). – Behrang Nov 11 '22 at 09:36
  • The error from the compiler is ***not*** "TypeError: Cannot add property 0, object is not extensible". TypeError is a runtime JavaScript error. I've already supplied you with a demo of it. I don't know why you insist on the problem not being that. It's provably incorrect. The `never[]` issue is *different* and not related to what the question here asks. As I said - changing the type information will *not* solve the issue that the object is frozen at runtime. It is actively misleading as it does not reflect the immutability. See correct behaviour here: https://tsplay.dev/m0n1Rw – VLAZ Nov 11 '22 at 09:58
  • Hi, in the [example](https://www.typescriptlang.org/play?#code/MYewdgzgLgBAnjAvDA3gKBpmBDAXDAbQF00BfNNOAOmyoAcBXCACwAoBGASiA) in my comment above, we can see the JavaScript produced by the TypeScript compiler on the right side of the screen. It looks like this: `const y = { a: [] };`. We can see that `a` is not frozen. If we feed this code to a JavaScript interpreter, we can see that we can add and remove elements from `a` without any issues. Yes, I know we can't add elements to a frozen array, but TypeScript does not compile that array into a frozen JS array. – Behrang Nov 11 '22 at 10:14
  • And I'm saying that you're wrong. Because OP gets a runtime error that only ever comes up if the object is frozen. I have already proven that the error reported in the question is that. Your example therefore does not match what the question describes. Proven by not getting a TypeError on running the code. I don't know why you are trying to convince me of something that is factually incorrect. None of your examples deal with the actual error that was reported. Are you trying to claim that the question asker does *not* get a TypeError and is lying to us? Can you prove it? – VLAZ Nov 11 '22 at 10:18
  • Okay, I reread the OP's questions and your comments and yes, you are correct. The OP's problem is a runtime error not a compile time error. – Behrang Nov 11 '22 at 10:34
0

So in my case this post helped

Material-table TypeError: Cannot add property tableData, object is not extensible

As VLAZ mentioned, the object gets freezed, so I cloned the object using

const cloneData = structuredClone(object);

and everything started working.

jeril
  • 1,109
  • 2
  • 17
  • 35