创建自定义Angular FormGroup时遇类型不匹配,如何修复?
修复Angular自定义FormGroup的类型不匹配问题
问题背景
我想为自定义Angular FormGroup添加专属方法,于是创建了继承默认FormGroup的UnitFormGroup类,期望它与IUnitForm类型一致。代码如下:
initForm(): FormGroup<IForm> { return this.formBuilder.group<IForm>({ weight: new UnitFormGroup<MassUnit>({ unit: new FormControl<MassUnit>(MassUnit.gram), unitValue: new FormControl<number>(11) } as IUnitForm<MassUnit>) }); } export interface IForm { weight: UnitFormGroup<UnitType>; } export class UnitFormGroup<T extends UnitType> extends FormGroup implements IUnitForm<T> { unit: FormControl<T>; unitValue: FormControl<number>; constructor(controls: IUnitForm<T>) { super(controls); this.unit = controls.unit; this.unitValue = controls.unitValue; } addOne(): void { const newValue = this.unitValue.value + 1; console.log(newValue); } } export type UnitType = MassUnit | LengthUnit | DistanceUnit | SpeedUnit | TemperatureUnit; export enum MassUnit { gram = 'gram', grain = 'grain', ounce = 'ounce' } export enum LengthUnit { millimeter = 'millimeter', inch = 'inch' } export enum DistanceUnit { meter = 'meter', yard = 'yard' } export enum SpeedUnit { meterSecond = 'meterSecond', feetSecond = 'feetSecond' } export enum TemperatureUnit { celsius = 'celsius', fahrenheit = 'fahrenheit' } export interface IUnitForm<T extends UnitType> { unit: FormControl<T>; unitValue: FormControl<number>; }
错误信息
在return this.formBuilder.group<IForm>处出现类型不匹配错误:
Type 'FormGroup<{ weight: FormGroup<{ [key: string]: AbstractControl<any, any>; }>; }>' is not assignable to type 'FormGroup<IForm>'. Types of property 'controls' are incompatible. Type '{ weight: FormGroup<{ [key: string]: AbstractControl<any, any>; }>; }' is not assignable to type 'IForm'.ts(2322)
修复方案
方案1:显式类型断言
直接对formBuilder.group的结果断言为目标类型,快速解决类型不匹配:
initForm(): FormGroup<IForm> { return this.formBuilder.group({ weight: new UnitFormGroup<MassUnit>({ unit: new FormControl<MassUnit>(MassUnit.gram), unitValue: new FormControl<number>(11) }) }) as FormGroup<IForm>; }
方案2:修正UnitFormGroup的继承泛型
让UnitFormGroup直接继承带泛型参数的FormGroup<IUnitForm<T>>,同时调整IForm的泛型类型匹配实际使用的单位:
// 修改UnitFormGroup的继承 export class UnitFormGroup<T extends UnitType> extends FormGroup<IUnitForm<T>> implements IUnitForm<T> { unit: FormControl<T>; unitValue: FormControl<number>; constructor(controls: IUnitForm<T>) { super(controls); this.unit = controls.unit; this.unitValue = controls.unitValue; } addOne(): void { const newValue = this.unitValue.value + 1; console.log(newValue); } } // 调整IForm的定义,指定具体的MassUnit export interface IForm { weight: UnitFormGroup<MassUnit>; }
这样formBuilder.group会自动识别weight的类型为UnitFormGroup<MassUnit>,与IForm的定义完全匹配。
方案3:扩展FormBuilder(适合多次使用场景)
如果需要频繁创建UnitFormGroup,可以扩展Angular的FormBuilder,添加专属方法避免重复类型处理:
// 在单独文件中扩展FormBuilder import { FormBuilder } from '@angular/forms'; import { UnitFormGroup, IUnitForm, UnitType } from './your-path'; declare module '@angular/forms' { interface FormBuilder { unitFormGroup<T extends UnitType>(controls: IUnitForm<T>): UnitFormGroup<T>; } } FormBuilder.prototype.unitFormGroup = function<T extends UnitType>(controls: IUnitForm<T>): UnitFormGroup<T> { return new UnitFormGroup<T>(controls); };
之后在组件中直接使用扩展后的方法:
initForm(): FormGroup<IForm> { return this.formBuilder.group<IForm>({ weight: this.formBuilder.unitFormGroup<MassUnit>({ unit: new FormControl<MassUnit>(MassUnit.gram), unitValue: new FormControl<number>(11) }) }); }
内容的提问来源于stack exchange,提问作者Gambon
相关产品推荐
相关产品推荐

