在 Angular 中,我们至少有两种方法可以访问子表单控件:FormGroup.get('controlPath')
或 FormGroup.controls.controlPath
。到目前为止,为了类型安全,我选择使用后者。
考虑到下面的代码:
ts
@Component({
selector: 'app-root',
templateUrl: './app/playground.component.html',
imports: [FormsModule, ReactiveFormsModule],
})
export class PlaygroundComponent {
formGroup = this.formBuilder.group({
booker: new FormControl('123', {validators: [Validators.required]}),
bookNames: this.formBuilder.array<string>([]),
bookerConf: this.formBuilder.group({language: ''})
});
constructor(private formBuilder: FormBuilder) {
const bookerFromControl = this.formGroup.controls.booker; // FormControl<string | null>
const bookerFromGetPath = this.formGroup.get('booker'); // AbstractControl<string | null, string | null> | null
const bookerFromGetPaths = this.formGroup.get(['booker']); // AbstractControl<any, any> | null
const bookerFromGetPathsWithConst = this.formGroup.get(['booker'] as const); // AbstractControl<string | null, string | null> | null
const bookNameFromControls = this.formGroup.controls.bookNames; // FormArray<FormControl<string | null>>
const bookNamesFromPath = this.formGroup.get('bookNames'); // AbstractControl<(string | null)[], (string | null)[]> | null
const bookNamesFromPaths = this.formGroup.get(['bookNames']); // AbstractControl<any, any> | null
const bookNamesFromPathsWithConst = this.formGroup.get(['bookNames'] as const); // AbstractControl<(string | null)[], (string | null)[]> | null
}
}
如你所见,formGroup.get
至少有两个问题
-
无法识别是否存在
booker
字段,因此bookerFromGetPath
的类型可能是null
- 当键入错误的表单控件名称时,例如
formGroup.get('booker1')
,不会有任何错误提示。 - 同样,当你想要利用 VSCode 的重构功能对
booker
字段名称进行批量修改时,formGroup.get('booker')
并不会被自动改掉。 - 使用路径数组参数时类型变得更糟,如
formGroup.get(['booker'])
。但对于这种情况,我们可以使用as const
,例如formGroup.get(['booker'] as const)
来改善这种情况。
- 当键入错误的表单控件名称时,例如
-
bookerFromGetPath
返回了错误的类型,AbstractControl
而不是FormControl
。- 这不是一个大问题,因为
AbstractControl
类似于FormControl
。 - 但是对于
bookNameFromControls
,FormArray
和AbstractControl
之间的差异很大。
- 这不是一个大问题,因为
有一个开放的问题 严格类型的 FormGroup 应该有严格类型的 "get" 访问器 在2024年11月16日提出。
截至2025年4月20日,这个问题仍未解决,而且该问题只关注了我们发现的第一个问题。
不管怎样,这就是我选择的原因。