Angular中*ngIf判断空数组仍触发TS2339编译错误求助
刚入门TypeScript/Angular,跟着课程学习*ngIf的使用。讲师演示空数组示例时,*ngIf会因条件不满足跳过第一个<ul>,渲染第二个<ul>,但我的代码却出现TS2339编译错误。
相关代码
image-box.component.html
<div id="image-box"> <div class="left"> <img src="https://images.unsplash.com/photo-1606857521015-7f9fcf423740?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1740&q=80"/> <app-title></app-title> </div> <div class="right"> <h3>Contracts</h3> <ul *ngIf="contractInComponent.length > 0"> <li *ngFor="let contract of contractInComponent"> Service: {{ contract.service }} <br> Title: {{ contract.title }} </li> </ul> <ul *ngIf="contractInComponent.length == 0"> <li>Empty</li> </ul> </div> </div>
get-data.service.ts
import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class GetDataService { constructor() { } getContracts() { return []; } }
image-box.component.ts
import { Component, OnInit } from '@angular/core'; import { GetDataService } from './get-data.service'; @Component({ selector: 'app-image-box', templateUrl: './image-box.component.html', styleUrls: ['./image-box.component.scss'] }) export class ImageBoxComponent implements OnInit { contractInComponent; constructor(service: GetDataService) { this.contractInComponent = service.getContracts(); } ngOnInit() {} }
编译错误信息
ERROR src/app/image-box/image-box.component.html:12:38 - error TS2339: Property 'service' does not exist on type 'never'. 12 Service: {{ contract.service }} <br> ~~~~~~~ src/app/image-box/image-box.component.ts:7:16 7 templateUrl: './image-box.component.html', ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Error occurs in the template of component ImageBoxComponent. ERROR src/app/image-box/image-box.component.html:13:36 - error TS2339: Property 'title' does not exist on type 'never'. 13 Title: {{ contract.title }} ~~~~~ src/app/image-box/image-box.component.ts:7:16 7 templateUrl: './image-box.component.html', ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Error occurs in the template of component ImageBoxComponent.
测试情况
将*ngIf改为直接使用布尔值(*ngIf="false"和*ngIf="true")时,代码可正常编译,第一个<ul>被忽略,第二个<ul>输出0:
修改后的image-box.component.html
<div id="image-box"> <div class="left"> <img src="https://images.unsplash.com/photo-1606857521015-7f9fcf423740?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1740&q=80"/> <app-title></app-title> </div> <div class="right"> <h3>Contracts</h3> <ul *ngIf="false"> <li *ngFor="let contract of contractInComponent"> Service: {{ contract.service }} <br> Title: {{ contract.title }} </li> </ul> <ul *ngIf="true"> <li>{{ contractInComponent.length }}</li> <!-- output = 0 --> </ul> </div> </div>
解决方法
问题根源
TypeScript的类型推断机制导致:getContracts()返回空数组时,TypeScript会将其推断为never[]类型(表示永远不会有元素的数组)。模板中尝试访问contract.service和contract.title时,TypeScript认为never类型不存在这些属性,因此抛出TS2339错误。
而当*ngIf直接写false时,Angular模板编译器会跳过该区块的类型检查,所以不会报错。
具体修复步骤
定义合约类型接口
在get-data.service.ts中添加Contract接口,明确合约对象的结构:import { Injectable } from '@angular/core'; // 定义合约类型 interface Contract { service: string; title: string; } @Injectable({ providedIn: 'root' }) export class GetDataService { constructor() { } // 指定返回类型为Contract数组 getContracts(): Contract[] { return []; } }在组件中指定数组类型
修改image-box.component.ts,给contractInComponent指定类型:import { Component, OnInit } from '@angular/core'; import { GetDataService } from './get-data.service'; // 导入Contract接口 import type { Contract } from './get-data.service'; @Component({ selector: 'app-image-box', templateUrl: './image-box.component.html', styleUrls: ['./image-box.component.scss'] }) export class ImageBoxComponent implements OnInit { // 指定类型为Contract数组 contractInComponent: Contract[]; constructor(service: GetDataService) { this.contractInComponent = service.getContracts(); } ngOnInit() {} }(可选)优化*ngIf条件
可以把*ngIf="contractInComponent.length > 0"简化为*ngIf="contractInComponent.length",空数组的length为0,在布尔语境中会被视为false,效果一致。
这样修改后,TypeScript能正确识别数组元素的类型,模板中的属性访问就不会再报错,同时也符合TypeScript的类型安全原则。
内容的提问来源于stack exchange,提问作者Imy

