Angular报错:类型'ListePrea'缺少'Toto'必填属性'NUM'
问题根因
这个是TypeScript静态类型校验抛出的类型不匹配错误,核心问题有两个:
- 赋值两侧类型完全不兼容
你在组件中声明变量listPreas: Toto,TS会强制要求这个变量的值必须符合Toto类型结构:顶层必须存在NUM属性。
但你赋值的res.PREA类型是ListePrea,从你的类型定义看,ListePrea的顶层只有一个名为PREA的属性,NUM字段是定义在ListePrea.PREA这个内层对象上的,res.PREA本身顶层根本没有NUM属性,自然不满足Toto类型的必填要求,直接触发报错。 - 类型定义和业务逻辑不匹配
你定义的Toto类仅包含一个NUM字段,和接口返回的包含二十多个业务字段的明细结构完全不匹配,属于冗余的无效类型定义;同时你给listPreas设置初始值时,this.num还没从路由参数里获取到值(路由参数是在ngOnInit里才赋值的),parseInt(this.num + '')实际得到的是NaN,这个初始值本身也是无效的。
另外你对TS中接口和类的使用场景存在误区:如果只是要约束接口返回的JSON结构,用interface就足够了,HTTP请求返回的是普通JS对象,不会自动转为类的实例;只有当你需要给数据绑定实例方法、需要通过构造函数做初始化逻辑时,才需要用class。
修复方案
按以下步骤调整即可解决问题:
- 对齐接口结构修正类型定义
先根据接口实际返回的JSON结构调整ListePrea定义,如果接口返回的PREA节点下直接是NUM、CLER等业务字段,去掉多余的嵌套层:
export interface TotoResponse extends ApiResponse { PREA: ListePrea; } // 修正后去掉多余的PREA嵌套,字段直接和接口返回对齐 export interface ListePrea { CLER: string; NUM: number; REF_RBC: string; TYPE: string; QUANTITE: number; ISIN: string; TRADE_DATE: Date; RECEPTION_DATE: Date; STATUT: number; LABEL: string; SVM: number; COURS_MOYEN_ACHAT: number; PERSONNE_CONTACT: string; TEL: number; FAX: number; DATE: Date; TRAITEMENT_DATE: Date; ANNULATION_DATE: Date; INTITULE1: string; CONTREPARTIE: string; TIS: number; CHANGEMENT_BENEF_ECO: string; REM1: string; REM2: string; }
如果接口返回的真实结构确实是res.PREA.PREA下才是业务字段,这步可以跳过,赋值的时候取对内层属性即可。
之前定义的Toto类因为结构不匹配、没有实际作用,可以直接删除。
- 修正组件中的变量声明和赋值逻辑
把listPreas的类型改为和接口返回一致的ListePrea,去掉无效的初始值,赋值时对齐层级:
export class TotoComponent implements OnInit, OnDestroy { private unsubscribe$ = new Subject<void>(); num: string | null = null; // 初始值设为null,类型和接口返回结构对齐 listPreas: ListePrea | null = null; constructor( private service: TotoService, private createDateTimePipe: CreateDateTimePipe, private location: Location, private activatedRoute: ActivatedRoute ) {} ngOnInit(): void { this.num = this.activatedRoute.snapshot.paramMap.get('num'); if (!this.num) { this.goBack(); return; } this.getTransferDetails(); } ngOnDestroy(): void { this.unsubscribe$.next(); this.unsubscribe$.complete(); } private getTransferDetails(): void { this.service.getTransferDetails(this.num!).pipe( takeUntil(this.unsubscribe$) ).subscribe(res => { if (res.RETURNCODE === ApiResponseCodeEnum.Ok) { // 如果第一步去掉了ListePrea的嵌套层,直接赋值res.PREA即可 this.listPreas = res.PREA; // 如果保留了ListePrea的嵌套结构,就取内层属性赋值 // this.listPreas = res.PREA.PREA; } }); } goBack(): void { this.location.back(); } }
内容的提问来源于stack exchange,提问作者Menier
相关产品推荐
相关产品推荐

