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

Angular8升级到12后报错:Property 'controls' does not exist on type 'AbstractControl'

报错原因

Angular 12及以上版本收紧了响应式表单的类型校验规则,你遇到的报错本质是类型不匹配:

  • FormArray的controls属性返回的数组元素类型为AbstractControl
  • AbstractControl是FormControl、FormGroup、FormArray的公共父类,本身没有controls属性,只有FormGroup子类才有该属性
  • Angular 8版本对该场景的类型检查宽松,所以代码可以正常运行,升级后强类型检查触发了报错

解决方案

以下三种方案均可解决问题,按推荐度排序:

方案1:自定义类型转换管道(最推荐,保留类型校验能力)

第一步:新增一个纯管道用于类型转换,代码如下:

// to-form-group.pipe.ts
import { Pipe, PipeTransform } from '@angular/core';
import { AbstractControl, FormGroup } from '@angular/forms';

@Pipe({ name: 'toFormGroup' })
export class ToFormGroupPipe implements PipeTransform {
  transform(control: AbstractControl): FormGroup {
    return control as FormGroup;
  }
}

第二步:将该管道添加到对应模块的declarations数组中。
第三步:模板内使用管道转换类型,修改后的代码示例:

<div *ngFor="let ticket of t.controls; let i = index">
  <div [formGroup]="ticket | toFormGroup" class="form-row">  
    <div class="input-group col-md-12" style="padding: .15em .5em">                                        
      <div class="input-group-prepend col-md-10" style="padding: 0; margin: 0;">                
        <label class="input-group-text w-15">{{i + 1}}</label>
        <label class="input-group-text w-100" style="text-align: left; white-space: normal;">
          {{(ticket | toFormGroup).controls.name.value}}
        </label>
      </div>                                 
      <select formControlName="controlName" class="form-control col-md-2" style="height:auto !important;" 
        [ngClass]="{ 'is-invalid': submitted && (ticket | toFormGroup).controls.controlName.errors }"
        (change)="onChange($event.target.value, i)">
        <option [ngValue]="null"> --Select-- </option>
        <option *ngFor="let ansItem of formdetail.questionList[i].answerList" [ngValue]="ansItem" >{{ansItem.anstext}}</option>
      </select>
      <div *ngIf="submitted && (ticket | toFormGroup).controls.controlName.errors" class="invalid-feedback" style="height:auto !important;" 
      [ngClass]="{ 'input-group-append': submitted && (ticket | toFormGroup).controls.controlName.errors,
                   'col-md-1': submitted && (ticket | toFormGroup).controls.controlName.errors }">
        <div *ngIf="(ticket | toFormGroup).controls.controlName.errors.required">Required</div>
      </div>
    </div>  
  </div>
</div>

方案2:组件内新增类型转换方法

在组件ts文件中新增转换方法:

getAsFormGroup(control: AbstractControl): FormGroup {
  return control as FormGroup;
}

模板内调用该方法即可,使用逻辑和方案1的管道一致,将ticket | toFormGroup替换为getAsFormGroup(ticket)即可。

方案3:使用$any()绕过类型检查(最快,不推荐长期使用)

Angular模板内置的$any()方法可以临时关闭变量的类型检查,修改写法如下:

{{$any(ticket).controls.name.value}}
[ngClass]="{ 'is-invalid': submitted && $any(ticket).controls.controlName.errors }"

补充说明

你之前尝试的ticket.get('controlName')写法本身是正确的,未生效大概率是没有加可选链运算符?.,正确写法为:

[ngClass]="{ 'is-invalid': submitted && ticket.get('controlName')?.errors }"

另外注意你提供的模板代码里有一个笔误:</div>写成了/div>,需要修正避免编译报错。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 12:24:03