Error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value

nick gowdy picture nick gowdy · Jul 30, 2018 · Viewed 9.5k times · Source

I'm using an auth guard in angular 5 to check if the user should be able to navigate to a specific page. I am getting an error related to returning an observable:

A function whose declared type is neither 'void' nor 'any' must return a value.

This is my authguard.ts

import { Injectable } from '@angular/core'; import { Router, CanActivate, ActivatedRoute, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; import { ApplicationVerificationService } from '../../service/application-verification.service';

@Injectable() export class AppStatusGuard implements CanActivate {

  applicationId: number;   personId: number;

  constructor(
    public router: Router,
    public readonly activeRoute: ActivatedRoute,
    public readonly applicationVerificationService: ApplicationVerificationService) { }

  loginRoute: boolean;   memberRoute: boolean;


  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {

    this.applicationId = Number(route.params["applicationId"]);
    this.personId = Number(route.params["personId"]);

    // Make sure they are allowed on this page, if not re-direct
    const url = this.applicationVerificationService.getRouteForFellowshipApplicant(this.personId, this.applicationId)
      .subscribe((res: string) => {
        console.log(url);

        if (res !== `application-status/${this.personId}/${this.applicationId}`) {
          console.log("failure");
          // this.router.navigateByUrl(url);
          return false;
        } else {
          console.log("success");
          //this.router.navigateByUrl(url);
          return true;
        }
      });   
  }; 
};

This is my verification service

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Router } from '@angular/router';
import 'rxjs/Rx';
import { Observable } from 'rxjs/Observable';

@Injectable()
export class ApplicationVerificationService {
  constructor(
    private readonly httpClient: HttpClient,
    private readonly router: Router) { }

  getRouteForFellowshipApplicant(personId, applicationId): Observable<string> {
    this.httpClient.get('api/application-verification/' + personId).subscribe((responseObject: IFellowshipApplicationStatus) => {

      return Observable.create(observer => {

        if (responseObject.preApplicationVerificationStatus === 'GoToTrackerPage') {
          observer.next('application-status/' + personId + '/' + applicationId);
        }
        if (responseObject.preApplicationVerificationStatus === 'GoToApplicationFormPage') {
          observer.next('application-form/' + personId + '/' + applicationId);
        }
        if (responseObject.preApplicationVerificationStatus === 'GoToContactIceForInfoPage') {
          observer.next('contact-us/' + personId + '/' + applicationId);
        }
        if (responseObject.preApplicationVerificationStatus === 'GenericError') {
          observer.next('application-error/' + personId);
        }
        observer.complete();
      });
    });
    return null;
  }
}

I'm new to rxjs and I think I've made an error with how I am returning observable but I'm struggling a bit. Any help would be appreciated.

Answer

user4676340 picture user4676340 · Jul 30, 2018

This will resolve your issue.

Your issue was that you aren't returning anything, and you are subscribing to your HTTP call. Instead, return the Observable itself, and use pipe(map(...)) to perform actions after your HTTP call without interrupting the chain of actions like subscribe does.

return this.applicationVerificationService.getRouteForFellowshipApplicant(this.personId, this.applicationId)
  .pipe(map(res => {
    console.log(url);

    if (res !== `application-status/${this.personId}/${this.applicationId}`) {
      console.log("failure");
      // this.router.navigateByUrl(url);
      return false;
    } else {
      console.log("success");
      //this.router.navigateByUrl(url);
      return true;
    }
  }));   
};