TypeScript联合类型报错:Property 'options'不存在,求优化方案
几个更优雅的解决方法
1. 用「可辨识联合」做类型守卫(最推荐)
你已经给两个字段类型加了type这个“辨识标签”('number'、'select'/'select-multi'),这简直是为TypeScript的类型守卫量身定做的!
首先在组件里加一个类型守卫函数:
isSelectField(field: Field): field is SelectField { // 靠type标签判断是不是选择器字段 return field.type === 'select' || field.type === 'select-multi'; }
然后在模板里用*ngIf配合这个守卫,让TypeScript明确知道当前字段是SelectField,就能安全访问options了:
<mat-form-field class="input"> <mat-select formControlName="state"> <!-- 先判断类型,再渲染 --> <ng-container *ngIf="isSelectField(getField('state'))"> <mat-option *ngFor="let option of getField('state').options" [value]="option.value" > {{option.viewValue}} </mat-option> </ng-container> </mat-select> </mat-form-field>
要是不想多次调用getField,可以提前把字段存到组件属性里:
// 组件类里 stateField: Field | undefined; ngOnInit() { this.stateField = this.getField('state'); }
模板就更简洁了:
<mat-form-field class="input" *ngIf="stateField"> <mat-select formControlName="state"> <mat-option *ngFor="let option of stateField.options" [value]="option.value" *ngIf="isSelectField(stateField)" > {{option.viewValue}} </mat-option> </mat-select> </mat-form-field>
2. 给getField加类型参数,返回精准类型
你可以改造getField,让调用者能指定想要的字段类型,结合辨识标签做判断:
getField<T extends Field>(key: string, expectedType: T['type']): T | undefined { const field = this.fields.find(el => el.id === key); // 验证类型是否匹配,匹配就返回对应类型 if (field && field.type === expectedType) { return field as T; } return undefined; }
调用的时候直接指定类型:
// 组件类里 stateField = this.getField<SelectField>('state', 'select');
模板里直接访问stateField.options就行,TypeScript完全清楚它的类型,不会报错。
3. 模板里直接用类型断言(应急用,不推荐)
如果你百分百确定某个字段就是SelectField,可以在模板里直接加类型断言,但这种方式很脆弱——哪天字段类型改了,编译时不会报错,但运行时肯定炸:
<mat-form-field class="input"> <mat-select formControlName="state"> <mat-option *ngFor="let option of (getField('state') as SelectField).options" [value]="option.value" > {{option.viewValue}} </mat-option> </mat-select> </mat-form-field>
4. 提前分类存储字段
如果你的字段类型比较固定,初始化时就把不同类型的字段分开存:
// 组件类里 numberFields: NumberField[] = []; selectFields: SelectField[] = []; ngOnInit() { this.numberFields = this.fields.filter(f => f.type === 'number') as NumberField[]; this.selectFields = this.fields.filter(f => f.type === 'select' || f.type === 'select-multi') as SelectField[]; } // 专门获取选择器字段的方法 getSelectField(key: string): SelectField | undefined { return this.selectFields.find(f => f.id === key); }
模板里调用getSelectField('state'),直接访问options毫无压力。
内容的提问来源于stack exchange,提问作者Mattijs
相关产品推荐
相关产品推荐

