You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular 2+结合Redux使用Immer时无法修改嵌套对象quantity属性的报错求助

解决Immer无法修改嵌套类实例属性的只读错误

嘿,我来帮你搞定这个困扰你的Immer只读属性赋值错误!咱们先理清楚问题出在哪,再一步步解决。

问题根源

你碰到的TypeError: Cannot assign to read only property 'quantity' of object '[object Object]'主要有两个核心原因:

  1. CartCarModel是类实例,Immer默认不兼容:Immer对普通JS对象/数组的可变更新支持很好,但类实例的属性可能因为类的封装特性,或者Redux的状态冻结机制,导致在Immer的draft对象里依然处于只读状态。
  2. Reducer返回时的属性名写错了:你最后返回的是{ drinks: nextState },但你的CartState定义的属性明明是cars,这会导致状态完全没更新,甚至可能引发其他奇怪问题。

具体解决方案

方案1:把类实例转为普通对象(推荐)

Immer最适配普通JavaScript对象,所以咱们可以调整状态的定义方式:

  1. 先把CartCarModel改成接口(如果不需要类的方法,接口足够用):
export interface CartCar {
  carId: string;
  carModel: string;
  quantity: number;
  price: number;
}

export interface CartState { 
  readonly cars: CartCar[] 
}
  1. 如果必须保留CartCarModel类,在把实例加入状态时,用展开运算符转成普通对象:
// 比如添加购物车项时
const newCar = new CartCarModel('1', 'Model S', 1, 50000);
// 转成普通对象再dispatch
dispatch(addCar({ ...newCar }));
  1. 修正reducer的写法,去掉多余的Object.assign:
function reducerFunc(state: CartState, id: string, quantity: number) {
  const nextState = produce(state, draft => {
    // 一定要加判断,避免找不到对应项时报错
    const targetCar = draft.cars.find(d => d.carId === id);
    if (targetCar) {
      targetCar.quantity = quantity;
    }
  });
  // Immer的produce已经返回了全新的状态对象,直接返回就行
  return nextState;
}

方案2:让Immer支持你的类实例

如果你确实需要保留CartCarModel类,可以给类加上Immer的标记,告诉它这个类是可以被可变处理的:

  1. 导入Immer的immerable,并在类上添加静态属性:
import { immerable } from 'immer';

export class CartCarModel {
  // 标记这个类可以被Immer处理
  [immerable] = true;
  constructor(
    public carId: string, 
    public carModel: string, 
    public quantity: number, 
    public price: number
  ) { }
}
  1. 同样修正reducer里的属性名错误,去掉多余的合并逻辑:
function reducerFunc(state: CartState, id: string, quantity: number) {
  const nextState = produce(state, draft => {
    const targetCar = draft.cars.find(d => d.carId === id);
    if (targetCar) {
      targetCar.quantity = quantity;
    }
  });
  return nextState;
}

额外提醒

  • 永远要检查find的结果是否存在,不然找不到对应车辆时会触发另一个错误:Cannot set property 'quantity' of undefined。
  • Redux的状态是不可变的,Immer的作用就是让你用“写可变代码”的方式生成不可变状态,所以完全不需要再用Object.assign去手动合并状态,produce已经帮你生成了全新的状态对象。

内容的提问来源于stack exchange,提问作者user15242670

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 08:39:06