1

I want to create a route guard with canActive method and response after a few seconds. I use this:

export class GuardService implements CanActivate {

  constructor(private router: Router,
              private UserInfo: UserInfoService) { }

  canActivate(route: ActivatedRouteSnapshot,
              state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
    setTimeout(() => {
      this.router.navigate(['/']);
      return false;
    }, 2000);
  }
}

So this function is returning a false after 2 seconds. I expect to work properly but angular didn't compile the code and return the following error:

ERROR in src/app/services/guard.service.ts(14,44): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value.

it says the canActive should return a boolean, not in setTimeOut, But my guard is an async guard and responding with delay is ok.

NTP
  • 4,338
  • 3
  • 16
  • 24
Leo
  • 867
  • 1
  • 15
  • 41

2 Answers2

1

Since it returns either a promise, an Observable or a boolean, maybe you could take advantage of that, don't you think ?

If you want to use promises (which I don't recommend), go like this

canActivate(...) {
  let p = new Promise((resolve, reject) => {
    setTimeout(() => resolve(true), 2000);
  });
  return p;
}

Now with Observables, which I recommend :

canActivate(...) {
  return Observable.of(true).delay(2000);
}
  • That's strange because it should, and doesn't help me resolve your issue. Could you elaborate on why it doesn't work ? –  Dec 11 '17 at 08:16
  • I explain the errors [here](https://gist.github.com/Alavi1412/1e8b82f3fefd6836d76c13ae075b7b73) – Leo Dec 11 '17 at 08:20
  • For the observable, add `import 'rxjs/add/operator/of';`. For the promise, you have to type it with `let p = new Promise` –  Dec 11 '17 at 08:40
1

Here is the code sample above refactored to return a Promise. Typescript was complaining first becaus your function didn't return anything, and you told it you were going to return either Observable, Promise or boolean. But you also can't just return the Timer object, so I wrapped the timer in a promise, keeping the same router logic to navigate to "/". Let me know if this works. Notice that inside the setTimeout, it doesn't return the boolean anymore it resolves with that value.

export class GuardService implements CanActivate {

  constructor(private router: Router,
              private UserInfo: UserInfoService) { }

  canActivate(route: ActivatedRouteSnapshot,
              state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
    return new Promise((resolve) => {
      setTimeout(() => {
        this.router.navigate(['/']);
        resolve(false); 
      }, 2000);
    })
  }
}
Brendan Whiting
  • 494
  • 3
  • 13