Angular HTTP拦截器报错:Type 'unknown'无法赋值给'HttpEvent<any>'
问题描述
在Angular应用中实现加载Spinner时,按照旧教程编写HTTP拦截器的intercept函数,第一个catchError管道正常,但第二个map管道出现类型错误,错误信息如下:
Argument of type 'OperatorFunction<HttpEvent<any>, any>' is not assignable to parameter of type 'OperatorFunction<unknown, any>'. Type 'unknown' is not assignable to type 'HttpEvent<any>'.ts(2345)
VSCode和Visual Studio中均出现该错误,推测是2020年后Angular Observable机制更新导致。相关拦截器代码如下:
import { Injectable } from '@angular/core'; import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor, HttpResponse } from '@angular/common/http'; import { Observable } from 'rxjs'; import { catchError, map } from 'rxjs/operators' import { LoadingService } from './loading.service'; /** * This class is for intercepting HTTP requests. When a request starts, we set the loadingSub property * in the LoadingService to true. Once the request completes and we have a response, set the loadingSub * property to false. If an error occurs while servicing the request, set the loadingSub property to false. * @class {HttpRequestInterceptor} */ @Injectable() export class HttpRequestInterceptor implements HttpInterceptor { constructor( private _loading: LoadingService ) { } intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { this._loading.setLoading(true, request.url); return next.handle(request) .pipe(catchError((err) => { this._loading.setLoading(false, request.url); return err; })) .pipe(map<HttpEvent<any>, any>((evt: HttpEvent<any>) => { if (evt instanceof HttpResponse) { this._loading.setLoading(false, request.url); } return evt; })); } }
解决方法
问题出在catchError的返回值处理上——新版本RxJS要求catchError回调必须返回Observable类型,直接返回err会让后续流的类型被推断为unknown,和map期望的HttpEvent<any>类型不兼容,才触发了这个错误。
按以下步骤修改即可解决:
- 先确保导入
throwError工具函数:
import { Observable, throwError } from 'rxjs';
- 修改
catchError的返回逻辑,用throwError包装错误对象,保证流的类型一致性:
.pipe(catchError((err) => { this._loading.setLoading(false, request.url); return throwError(() => err); // 用throwError包装后返回Observable,不破坏原流类型 }))
- (可选优化)把两个
pipe调用合并成一个,让代码更简洁:
return next.handle(request) .pipe( catchError((err) => { this._loading.setLoading(false, request.url); return throwError(() => err); }), map((evt: HttpEvent<any>) => { if (evt instanceof HttpResponse) { this._loading.setLoading(false, request.url); } return evt; }) );
修改完成后,类型错误会消失,因为catchError现在返回的是符合规范的Observable,后续map能正确识别输入类型为HttpEvent<any>。
内容的提问来源于stack exchange,提问作者nbofni
相关产品推荐
相关产品推荐

