Angular发布报错:tipoInstrumento不存在于Instrumento类型 问题排查
Angular项目发布时模板类型识别错误解决方案
问题背景
之前instrumentoPipe管道的返回值为Instrumento类型,使用ngFor实现表格列表渲染时,调试阶段运行完全正常,但执行项目发布操作时抛出如下错误:
Property 'tipoInstrumento' does not exist on type 'Instrumento'. Did you mean 'idInstrumento'?
已经在组件中定义了InstrumentoTipoInstrumento接口,且对instrumentos数组做了映射处理,明确包含tipoInstrumento字段,但模板中遍历得到的instrumento条目被识别为项目中另一个Instrumento模型类型,而非预期的InstrumentoTipoInstrumento类型。
相关代码
Instrumento.component.html
</div><div class="main-content"> <div class="row"> <div class="col-md-12"> <div class="card"> <div class="card-title"> </div> <div class="card-body"> <h2>Instrumentos</h2> <p *ngIf="!instrumentos"><mat-spinner></mat-spinner></p> <div class="row align-items-center"> <div class="col-md-1 text-center"> <a *ngIf="instrumentos" routerLink="create/0" class="btn bs-tooltip-right"><i class="fas fa-address-card"></i> Crear</a> </div> <div class="col-md-6"> <input class="form-control buscador" placeholder="Buscar instrumento" id="buscador" name="buscador" [(ngModel)]="value" > </div> </div> <table class='table table-hover' aria-labelledby="tableLabel" *ngIf="instrumentos"> <thead> <tr> <th>Nombre instrumento</th> <th>Tipo instrumento</th> </tr> </thead> <tbody> <tr *ngFor="let instrumento of instrumentos|instrumentoPipe:value; let i = index"> <td>{{ instrumento.nombreInstrumento }}</td> <td>{{ instrumento.tipoInstrumento }}</td> <td><a [routerLink]="['edit', instrumento.idInstrumento]" class="btn btn-info"><i class="fas fa-edit"></i> Editar</a></td> <td><a (click)="deleteInstrumento(instrumento.idInstrumento)" class="btn btn-danger"><i class="fas fa-trash"></i> Eliminar</a></td> </tr> </tbody> </table> </div> </div> </div> </div> </div>
instrumento.component.ts
import { Component, OnInit } from '@angular/core'; import { ThemePalette } from '@angular/material/core'; import { ProgressSpinnerMode } from '@angular/material/progress-spinner'; import { ActivatedRoute } from '@angular/router'; import { ToastrService } from 'ngx-toastr'; import { TipoInstrumento } from '../models/tipo-instrumento'; import { InstrumentoService } from '../services/instrumento.service'; import { TipoInstrumentoService } from '../services/tipo-instrumento.service'; @Component({ selector: 'instrumento', templateUrl: './instrumento.component.html', styleUrls: ['./instrumento.component.css'] }) export class InstrumentoComponent implements OnInit { instrumentosSC: any[]; instrumentos: InstrumentoTipoInstrumento[]; tipoInstrumento: TipoInstrumento[]; color: ThemePalette = 'primary'; mode: ProgressSpinnerMode = 'indeterminate'; value: string = ''; constructor(private toastr: ToastrService, private instrumentoService: InstrumentoService, route: ActivatedRoute, private tipoInstrumentoService: TipoInstrumentoService) { } getInstrumento() { this.instrumentoService.GetInstrumento().subscribe(result => this.getTipoInstrumentos(result), error => this.toastr.error("Hubo un error al cargar los instrumentos" + error, "Error")); } deleteInstrumento(id: number) { this.instrumentoService.DeleteInstrumento(id).subscribe(result => this.toastr.success("Instrumento eliminado exitosamente", "Éxito"), error => this.toastr.error("Hubo un error al eliminar el instrumento " + error, "Error")); } getTipoInstrumentos(result) { this.instrumentosSC = result; this.tipoInstrumentoService.GetTipoInstrumento().subscribe(result => this.mapInstrumentos(result), error => this.toastr.error("Hubo un error al cargar Tipo Instrumento" + error, "Error")); } mapInstrumentos(result) { this.tipoInstrumento = result; this.instrumentos = this.instrumentosSC.map(instrumento => { return { idInstrumento: instrumento.idInstrumento, nombreInstrumento: instrumento.nombreInstrumento, tipoInstrumentoIdTipoInstrumento: instrumento.tipoInstrumentoIdTipoInstrumento, tipoInstrumento: this.getTipoInstrumentoById(instrumento.tipoInstrumentoIdTipoInstrumento).nombreTipoInstrumento } }) } ngOnInit() { this.getInstrumento(); } getTipoInstrumentoById(id: number) { console.log(id); return this.tipoInstrumento.find(tipoInstrumentos => { return tipoInstrumentos.idTipoInstrumento === id; }) } } interface InstrumentoTipoInstrumento { idInstrumento?: number; nombreInstrumento: string; tipoInstrumentoIdTipoInstrumento: number; tipoInstrumento: string; }
问题根源
Angular调试阶段默认使用JIT编译,类型检查较为宽松,而发布时会启用AOT编译,会对模板做严格的类型校验。你的instrumentoPipe管道返回值类型仍然声明为旧的Instrumento[],导致经过管道处理后的数组类型被推断为Instrumento[],和你组件中定义的InstrumentoTipoInstrumento[]不匹配,因此抛出属性不存在的错误。
解决方案
- 首选方案:修改
instrumentoPipe管道的返回类型声明,将返回值从Instrumento[]调整为InstrumentoTipoInstrumento[],同步修改管道内部逻辑的类型注解,保证管道输出类型和组件定义的数组类型完全一致,从根源解决类型不匹配问题。 - 临时规避方案:如果暂时不方便修改管道定义,可以在模板中使用
$any方法做类型断言,修改ngFor写法即可:<tr *ngFor="let instrumento of $any(instrumentos|instrumentoPipe:value); let i = index"> - 优化建议:在
tsconfig.json中开启严格模板类型检查配置,开发阶段就能提前发现这类类型问题,无需等到发布阶段才暴露。
内容的提问来源于stack exchange,提问作者SANTIAGO SANCHEZ BERRIO
相关产品推荐
相关产品推荐

