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

Angular中赋值只读属性salaries触发TypeError的解决方案咨询

解决Angular中"Cannot assign to read only property 'salaries'"错误

问题原因

你遇到的错误是因为@Input()传入的profile对象是只读/不可变的(比如来自NgRx等状态管理库的冻结对象,或API返回时被设置为不可写的对象),直接修改它的属性会触发只读限制。你之前尝试的Object.defineProperty用法错误,因为你给salaries数组本身添加属性,而不是修改profile对象上salaries属性的可写性。

解决方案

1. 使用本地副本存储profile(推荐)

在组件内创建一个本地变量存储profile的拷贝,避免直接修改传入的只读对象:

export class ProfileFormComponent implements OnInit, OnDestroy {
  private _profile: ProfileModel;
  
  // 通过setter接收Input并创建副本
  @Input() set profile(value: ProfileModel) {
    // 浅拷贝对象和数组,解除与原对象的引用
    this._profile = {
      ...value,
      salaries: [...(value.salaries || [])]
    };
  }
  
  // 提供getter供模板使用
  get profile(): ProfileModel {
    return this._profile;
  }

  addSalary() {
    const salary: SalaryModel = {
      clientId: 1,
      profileId: this.profile.id,
      amount: this.salary.value,
      startDate: new Date(),
      endDate: null,
    };

    // 优化嵌套订阅:用switchMap合并请求
    this.apiService.profileService.addSalary(salary).pipe(
      switchMap(() => this.apiService.profileService.getProfile(this.profile.id))
    ).subscribe(pc => {
      // 修改本地副本的salaries
      this._profile.salaries = [...pc.salaries];
      this.resetDataForm();
    });
  }
}

模板无需修改,依然使用profile.salaries即可。

2. 临时修改属性可写性(不推荐)

如果必须直接修改传入的profile对象,可以调整Object.defineProperty的目标:

this.apiService.profileService.getProfile(this.profile.id).subscribe(pc=>{
  // 修改profile对象上salaries属性的可写性
  Object.defineProperty(this.profile, 'salaries', { writable: true });
  this.profile.salaries = [...pc.salaries];
  this.resetDataForm();
});

这种方式不推荐,因为它破坏了原对象的不可变性设计,可能引发其他潜在问题。

3. 替换整个profile对象

如果父组件允许接收更新后的profile,可以通过@Output通知父组件更新:

export class ProfileFormComponent implements OnInit, OnDestroy {
  @Input() profile: ProfileModel;
  @Output() profileChange = new EventEmitter<ProfileModel>();

  addSalary() {
    // ... 省略salary创建代码

    this.apiService.profileService.addSalary(salary).pipe(
      switchMap(() => this.apiService.profileService.getProfile(this.profile.id))
    ).subscribe(pc => {
      // 发送新对象给父组件
      this.profileChange.emit(pc);
      this.resetDataForm();
    });
  }
}

父组件使用时:

<app-profile-form [(profile)]="parentProfile"></app-profile-form>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 16:55:25