Angular 8升级至12后出现TypeError:"property" is read-only报错如何解决
报错原因
- Angular版本升级后编译模式变更:Angular 9及以上版本默认启用Ivy编译器,Angular 12已完全移除旧的ViewEngine。Ivy为了优化变更检测性能、强制遵循单向数据流规范,会对
@Input()传入的对象、数组做隐式冻结处理,禁止子组件直接修改输入属性的原始值,避免子组件意外修改父组件状态导致的不可预期问题。 - 代码写法不符合单向数据流要求:你提供的代码在
map遍历中直接修改了原area对象的属性,而该对象属于输入属性的原始值,触发了Ivy的只读校验规则,因此抛出属性只读错误。
修复方案
方案1:生成新对象副本,不修改原始值(最推荐)
这种写法完全符合Angular单向数据流的设计规范,不会产生副作用,后续版本升级也不会出现兼容问题。只需要在修改属性前先基于原对象生成新副本,修改副本后返回即可:
ngOnChanges(): void { this.Areas = this.areas .map(area => { // 浅拷贝生成新对象,嵌套对象可改用深拷贝实现 const newArea = {...area}; newArea.index = 10; switch (newArea.name) { case '1': newArea.index = 0; break; case '2': newArea.index = 1; break; case '3': newArea.index = 2; break; } return newArea; }) .sort((a, b) => (a.index - b.index)); }
如果对象是多层嵌套结构,可以用JSON.parse(JSON.stringify(area))做深拷贝,也可以引入第三方工具库的深拷贝方法(比如lodash的cloneDeep)。
方案2:为输入属性生成本地可变副本
如果不想修改原有遍历逻辑,可以在拿到输入属性后先拷贝一份存为本地可变变量,后续直接操作本地变量即可:
// 声明输入属性 @Input() areas: ObjectName[]; ngOnChanges(): void { // 先拷贝输入属性生成本地可变数组 const mutableAreas = [...this.areas]; this.Areas = mutableAreas .map(area => { // 原有逻辑无需修改 area.index = 10; switch (area.name) { case '1': area.index = 0; break; case '2': area.index = 1; break; case '3': area.index = 2; break; } return area; }) .sort((a, b) => (a.index - b.index)); }
方案3:关闭严格输入校验(临时兼容方案,不推荐长期使用)
如果项目中同类报错量极大,短期内无法逐个修改代码,可以通过调整编译配置关闭Ivy的输入属性只读校验,先保证项目正常运行:
在tsconfig.json中新增angularCompilerOptions配置项:
{ "compileOnSave": false, "compilerOptions": { // 原有配置保持不变 }, "angularCompilerOptions": { "strictInputAccessModifiers": false, "strictInputTypes": false } }
注意该方案仅作为临时过渡使用,长期来看还是建议修改代码符合Angular的数据流规范,避免后续版本升级出现更多兼容问题。
内容的提问来源于stack exchange,提问作者ArtoriasDF
相关产品推荐
相关产品推荐

