Angular RxJS可复用Pipe操作符结合泛型时TS无法识别属性问题
问题解决方法
报错原因
你定义的responseObserver方法中的泛型T没有设置任何类型约束,TypeScript默认会将无约束的泛型识别为任意类型,无法确定T一定包含response属性,因此抛出属性不存在的编译报错。即便调用时传入了具体的ItemApiResponse类型,无约束的泛型也不会自动继承该类型的属性特征。
解决方案
首先给泛型T增加类型约束,明确要求传入的类型必须是ApiGetResponse的子类,同时可以对thisArg增加类型约束,避免后续调用时传入不符合要求的实例:
// 首先定义公共服务需要实现的接口,约束thisArg的类型 interface IBaseApiService { _loadingSubject: Subject<boolean>; _errorSubject: Subject<boolean>; _emptySubject: Subject<boolean>; } // 给泛型T增加extends约束,限定为ApiGetResponse的子类 function responseObserver<T extends ApiGetResponse<any>>(thisArg: IBaseApiService) { return pipe( map((res: T) => { // 此时TypeScript可正确识别res上的response属性 if(res.response?.items?.length === 0) { thisArg._emptySubject.next(true); } return res; }), catchError((err: ApiErrorResponse) => { thisArg._errorSubject.next(true); return throwError(err); }), finalize(() => thisArg._loadingSubject.next(false)) ); }
可选优化
如果有大量同类型的接口服务,可以抽离公共基础服务类,所有业务接口服务继承该类即可自动适配thisArg的类型要求,无需每个服务单独实现接口:
export abstract class BaseApiService implements IBaseApiService { protected _loadingSubject = new Subject<boolean>(); protected _errorSubject = new Subject<boolean>(); protected _emptySubject = new Subject<boolean>(); // 也可以直接把responseObserver放到基类里,不用每次传this protected responseObserver<T extends ApiGetResponse<any>>() { return pipe( map((res: T) => { if(res.response?.items?.length === 0) { this._emptySubject.next(true); } return res; }), catchError((err: ApiErrorResponse) => { this._errorSubject.next(true); return throwError(err); }), finalize(() => this._loadingSubject.next(false)) ); } }
调用时直接调用基类方法即可:
return this.http .post<ItemApiResponse>(`${environment._API_}/Some/Api/Endpoint`, { userId }) .pipe(this.responseObserver<ItemApiResponse>());
该方案完全兼容TypeScript 3.8版本,无需升级TS版本。
内容的提问来源于stack exchange,提问作者henrik123
相关产品推荐
相关产品推荐

