Home > Net >  Angular intercept returning error, problem with types
Angular intercept returning error, problem with types

Time:08-18

Creating HR Manager app using Angular for frontend and .NET for backend. I get error from assigning type in interceptor for HttpRequests.

auth.interceptor.service.ts

import { Injectable } from '@angular/core';
import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest, HttpHeaders, HttpErrorResponse } from '@angular/common/http';
import { Observable, from, tap } from 'rxjs';
import { CoreModule } from './core.module';
import { AuthService } from './auth-service.component';
import { Constants } from '../constants';
import { Router } from '@angular/router';

@Injectable()
export class AuthInterceptorService implements HttpInterceptor {
  constructor(
    private _authService: AuthService,
    private _router: Router,  
  ) { }
  
  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    if (req.url.startsWith(Constants.apiRoot)) {
      return from(this._authService.getAccessToken().then(token => {
        const headers = new HttpHeaders().set('Authorization', `Bearer ${token}`);
        const authReq = req.clone({ headers });
        return next.handle(authReq).pipe(tap(_ => { }, error => {
          var respError = error as HttpErrorResponse;
          if (respError && (respError.status === 401 || respError.status === 403)) {
            this._router.navigate(['/unauthorized']);
          }
        })).toPromise();
      }));
    } else {
      return next.handle(req);
    }
  }
}

AuthService is service for handling login, logout, geting tokens and other needed function.

auth-service.component.ts

import { Injectable } from '@angular/core';
import { CoreModule } from './core.module';
import { UserManager, User } from 'oidc-client';
import { Constants } from '../constants';
import { Subject } from 'rxjs';

@Injectable()
export class AuthService {
    private _userManager: UserManager;
    private _user: User | undefined;
    private _loginChangedSubject = new Subject<boolean>();

    loginChanged = this._loginChangedSubject.asObservable();

    constructor() {
        const stsSettings = {
            authority: 'https://localhost:5443/',
            client_id: 'spa-client',
            redirect_uri: `${Constants.clientRoot}signin-callback`,
            scope: 'openid profile projects-api',
            response: 'id_token token',
            post_logout_redirect_uri: `${Constants.clientRoot}signout-callback`,
        };

        this._userManager = new UserManager(stsSettings);
    }

    login(): any {
        return this._userManager.signinRedirect();
    }

    isLoggedIn(): Promise<boolean> {
        return this._userManager.getUser().then(user => {
            const userCurrent = !!user && !user.expired;
            if (this._user !== user) {
                this._loginChangedSubject.next(userCurrent);
            }
            this._user = user!;
            return userCurrent;
        });
    }

    completeLogin() {
        return this._userManager.signinRedirectCallback().then(user => {
            this._user = user;
            this._loginChangedSubject.next(!!user && !user.expired);
            return user;
        });
    }

    logout() {
        this._userManager.signoutRedirect();
    }

    completeLogout() {
        this._user = null!;
        return this._userManager.signoutRedirectCallback();
    }

    getAccessToken() {
        return this._userManager.getUser().then(user => {
            if (!!user && !user.expired) {
                return user.access_token;
            } else {
                return null;
            }
        });
    }
}

I'm receiving this error:

Type 'Observable<HttpEvent<any> | undefined>' is not assignable to type 'Observable<HttpEvent<any>>'.
  Type 'HttpEvent<any> | undefined' is not assignable to type 'HttpEvent<any>'.
    Type 'undefined' is not assignable to type 'HttpEvent<any>'.ts(2322)

The error is caused here:

return from(this._authService.getAccessToken().then(token => {
        const headers = new HttpHeaders().set('Authorization', `Bearer ${token}`);
        const authReq = req.clone({ headers });
        return next.handle(authReq).pipe(tap(_ => { }, error => {
          var respError = error as HttpErrorResponse;
          if (respError && (respError.status === 401 || respError.status === 403)) {
            this._router.navigate(['/unauthorized']);
          }
        })).toPromise();
      }));

1

CodePudding user response:

'Observable<HttpEvent<any> | undefined>' is not assignable to type 'Observable<HttpEvent<any>>' means that you are assigning a nullable value to a non nullable type. This could be caused by the flag strictNullChecks set to true in your tsconfig.ts.

The solution is about using a type guard.

Supposing that yourVar has the Observable<HttpEvent<any> | undefined> type, if you are assigning a variable you should use:

let observable: Observable<HttpEvent<any>> = null;

if (yourVar) {
  observable = yourVar;
} else {
  // this requires a different handling!
}

If you are returning a value you should use:

fn(): Observable<HttpEvent<any>> = {
  if (yourVar) {
    return yourVar;
  }
  throw new Error(); // or a different handling that returns an observable
}

CodePudding user response:

In RxJS 7, the return type of the Observable's toPromise() method has been fixed to better reflect the fact that Observables can yield zero values. This may be a breaking change to some projects as the return type was changed from Promise<T> to Promise<T | undefined>. https://rxjs.dev/deprecations/to-promise

try this , do not use toPromise()

intercept(req: HttpRequest<any>, next: HttpHandler) {
    if (!req.url.startsWith(Constants.apiRoot)) {
      return next.handle(req);
    }
    return from(this._authService.getAccessToken()).pipe(
      switchMap((token) => next.handle(req.clone({ setHeaders: { Authorization: 'Bearer '   token } }))),
      catchError((error) => {
        if (error instanceof HttpErrorResponse && (error.status === 401 || error.status === 403)) {
          this._router.navigate(['/unauthorized']);
          return EMPTY; // if you wanna throw error comment out this line
        }
        return throwError(error);
      })
    );
  }
  • Related