Search code examples
javascriptangularangularjstypescriptangular-http-interceptors

Type 'unknown' is not assignable to type 'HttpEvent<any>' - Trying to create HTTP interceptor in Angular app


I have been trying to create a loading spinner in my Angular application.

I found an interesting tutorial here (https://medium.com/swlh/angular-loading-spinner-using-http-interceptor-63c1bb76517b).

It was all going pretty well, until the final step, when I need to actually create the intercept function.

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 {

    /**
     * 
     * @param _loading 
     */
    constructor(
        private _loading: LoadingService
    ) { }

    /**
    * Called at the start of every HTTP request. This function will try to activate the loading spinner
    * @param request 
    * @param next 
    * @returns 
    */
    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;
            }));
      }
}

The 1st pipe is fine.

However, there is a big red underline all over the 2nd pipe. The error states the following:

Argument of type 'OperatorFunction<HttpEvent, any>' is not assignable to parameter of type 'OperatorFunction<unknown, any>'. Type 'unknown' is not assignable to type 'HttpEvent'.ts(2345)

enter image description here

I am seeing the error in VSCode (blue one) and Microsoft VS (purple one), meaning there's definitely something wrong with my code rather than my IDE being weird...

The article was written in June 2020 (4 years ago), so perhaps there have been changes to how Angular observables work?

I have been learning Angular for about 1 week, and also not very familiar with typescript, so apologies if I am missing some fundamental knowledge, but would appreciate some guidance, as I am not sure how to proceed...

If the stackoverflow gurus have any advice it would be greatly appreciated.

Thanks!


Solution

  • The catchError, must return an observable, so I use of to convert the error to an observable, this is causing the errors downstream on the map.

      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 of(err);
          }),
          map<HttpEvent<any>, HttpEvent<any>>((evt: HttpEvent<any>) => {
            if (evt instanceof HttpResponse) {
              this._loading.setLoading(false, request.url);
            }
            return evt;
          })
        );
      }