无法分配给对象“#<Object>”的只读属性“property”

Pet*_*ard 2 javascript interface instance readonly typescript

我有这个问题。

带接口:

export interface IDevice {
  id: string,
  selected: boolean
}
Run Code Online (Sandbox Code Playgroud)

通过以下方式创建实例:

let newDevice: IDevice = {
  id: uuid4(),
  selected: false,
} as IDevice;
Run Code Online (Sandbox Code Playgroud)

它以反冲状态添加到数组中,并在 React 中用于使用 useRecoilState() 检索数组的函数中。 const [leftList, setLeftList] = React.useState<IDevice[]>([]);

现在它在处理程序中用于选择列表控件上的设备,这里发生错误:

...
leftList.map((item: IDevice) => {     
      if (item.id === event.dataItem.id) {
        item.selected = !item.selected;
      }
      return item;
    })
...
Run Code Online (Sandbox Code Playgroud)

我收到错误:无法分配给对象“#”的只读属性“选定”

即使先通过 [...leftList] 克隆数组也没有帮助。

我迷路了:-)希望有人能对此有所了解吗?

Nic*_*ons 7

不应直接修改状态,这就是您当前.map()通过更新对象在方法中所做的事情。TS 试图通过将对象设置为只读来告诉您不要这样做。

相反,您可以创建一个包含所有属性的新对象item(使用展开语法 ...完成),以及一个新的覆盖属性selected,如果 id 与事件的数据匹配,它将使用该项目当前所选项目的否定版本项目 id,否则它将保留原始选择的值:

leftList.map((item: IDevice) => ({
  ...item, 
  selected: item.id === event.dataItem.id ? !item.selected : item.selected
}))
Run Code Online (Sandbox Code Playgroud)

使用扩展语法([...leftList])克隆数组只会进行浅拷贝,不会对数组中的对象进行深拷贝,因此修改数组中的对象引用.map()仍然是修改原始状态。

或者,您可以只在想要修改属性时返回一个新创建的对象,而不是每次扩展对象并创建一个新对象(这可能会稍微影响性能,如@3limin4t0ritem指出的那样):selected

leftList.map((item: IDevice) => {     
  if (item.id !== event.dataItem.id) return item;
  return {...item, selected: !item.selected};
});
Run Code Online (Sandbox Code Playgroud)