Angular TS2322报错:Observable<{}>无法赋值为ITimesheetComments[]类型
问题描述
Angular开发过程中遇到TS类型报错,报错信息如下:
error TS2322: Type 'Observable<{}>' is not assignable to type 'Observable<ITimesheetComments[]>'. Type '{}' is missing the following properties from type 'ITimesheetComments[]': length, pop, push, concat, and 28 more.
业务逻辑为TimesheetCommentsService.getList()调用HttpService.getList(),预期返回ITimesheetComments[]类型的数据,相关代码如下:
timesheet-comments.services.ts 代码
import { ITimesheetComments } from './../models/timesheet-comments.model'; import { Injectable } from '@angular/core'; import { Observable } from 'rxjs/Observable'; import { ResourceParams } from '../../../core/http/models/resource-params.model'; import { HttpService } from '../../../core/http/http.service'; @Injectable() export class TimesheetCommentsService { constructor(private http: HttpService) { } getList(transactionRelatedNum : number) : Observable<ITimesheetComments[]> { let resourceParams : ResourceParams = new ResourceParams(); resourceParams.orderBy = "date_created desc"; let endpoint: string = `ServiceReceipts/${transactionRelatedNum}/Comments`; return this.http.getList<ITimesheetComments[]>(endpoint, resourceParams); } }
http.service.ts 相关代码
getList<T> (endpoint: string, resourceParams: ResourceParams = new ResourceParams(), headers ?: any, useOnlyEndpoint: boolean = false) { let url = `${(useOnlyEndpoint) ? '' : `${this.env.BASE_URL}/${this.URL_PATH}/`}${endpoint}${this.buildParams(resourceParams.toExtraParams())}` return from(this.appAuth.authenticateToken(this.token).then(() => this.httpGet(url, headers))) .pipe(map((response : HTTPResponse) => this.parseData<ITimesheetComments[]>(response)), catchError(error => this.handleError(error, 'Get'))); }
问题原因
报错根源是HttpService.getList()泛型方法实现存在问题,TypeScript无法正确推断返回类型,最终将返回值识别为Observable<{}>,和调用方要求的Observable<ITimesheetComments[]>类型不匹配:
- 方法虽然声明了泛型参数
<T>,但内部调用parseData时硬编码写死了ITimesheetComments[]类型,完全没有用到调用时传入的泛型参数T - 方法没有显式声明返回值类型,TS类型推断链路断裂,返回值直接退化为最宽泛的
Observable<{}>类型
修复方案
修改http.service.ts中的getList方法,做两处调整即可:
- 将
parseData的硬编码类型替换为泛型参数T - 给
getList方法显式标注返回类型Observable<T>
修改后的代码如下:
// 显式标注返回类型为Observable<T> getList<T> (endpoint: string, resourceParams: ResourceParams = new ResourceParams(), headers ?: any, useOnlyEndpoint: boolean = false): Observable<T> { let url = `${(useOnlyEndpoint) ? '' : `${this.env.BASE_URL}/${this.URL_PATH}/`}${endpoint}${this.buildParams(resourceParams.toExtraParams())}` return from(this.appAuth.authenticateToken(this.token).then(() => this.httpGet(url, headers))) // 用泛型T替换硬编码的ITimesheetComments[] .pipe(map((response : HTTPResponse) => this.parseData<T>(response)), catchError(error => this.handleError(error, 'Get'))); }
补充说明:修改后所有调用getList传入不同类型参数的场景都能正确获得类型推断,不需要为每个接口单独硬编码类型,符合泛型方法的设计初衷。
内容的提问来源于stack exchange,提问作者IanS
相关产品推荐
相关产品推荐

