0

Checkout this answer to understand the approach. I am using to the same solution to implement the master guard as I have multiple guards and want to execute them in sequence.

In Master Guard -

return guard.canActivate(this.route, this.state);

The whole function is Specified below:

//Create an instance of the guard and fire canActivate method returning a promise
    private activateGuard(guardKey: string): Promise<boolean> {

        let guard: Guard1 | Guard2 | Guard3 | Guard4;

        switch (guardKey) {
            case GUARDS.GUARD1:
                guard = new Guard1();
                break;
            case GUARDS.GUARD2:
                guard = new Guard2();
                break;
            case GUARDS.GUARD3:
                guard = new Guard3();
                break;
            case GUARDS.GUARD4:
                guard = new Guard4(this._Guard4DependencyService);
                break;
            default:
                break;
        }
        return guard.canActivate(this.route, this.state);
    }

I am getting the error mentioned below:

Type 'boolean | Observable<boolean>' is not assignable to type 'boolean'.
  Type 'Observable<boolean>' is not assignable to type 'boolean'.

Please find stackblitz link for the same

Screenshot shared below: I am getting this error as shown in screenshot Please share your solution to get rid of this error. Any help is appreciated thanks in advance!

5
  • You can simply add return type as boolean if guard.canActivate() is returning boolean value.. private activateGuard(guardKey: string): Promise<boolean> | boolean Commented Dec 31, 2021 at 5:38
  • Hi @DevangPatel I tried what you suggested but error still persist: Type 'boolean | Promise<boolean> | Observable<boolean>' is not assignable to type 'boolean | Promise<boolean>'. Type 'Observable<boolean>' is not assignable to type 'boolean | Promise<boolean>'. Type 'Observable<boolean>' is missing the following properties from type 'Promise<boolean>': then, catch, finally, [Symbol.toStringTag] Commented Dec 31, 2021 at 5:55
  • 1
    Can you share code on stackblitz? Commented Dec 31, 2021 at 6:02
  • @DevangPatel: stackblitz.com/edit/angular-route-guards-zkcvpm?file=src/app/… Also added in question Commented Dec 31, 2021 at 6:31
  • Just change the return type of your function to be boolean | Promise<boolean>, Angular Guards accept both. Commented Dec 31, 2021 at 8:10

2 Answers 2

1

I see your issue now. guard1 service and guard2 service are having two different return types. You need to have both return type as Promise<boolean> as per MasterGuard service code.

If you see activateGuard() in MasterGuard service then it is expecting for Promise<boolean>. However, in guard1 service, you have returned Observable<boolean>.

guard1.service.ts :

@Injectable()
export class Guard1 implements CanActivate, CanActivateChild {
  
  constructor(private router: Router) {}

  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<boolean> {
    console.log('Chain-1');
    return Promise.resolve(true)   // Modified this part
  }

  canActivateChild(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<boolean> {
    return this.canActivate(route, state);
  }
}

guard2.service.ts :

@Injectable()
export class Guard2 implements CanActivate, CanActivateChild {
  
  constructor() {}

  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<boolean> {
    console.log('Chain-2');
    return Promise.resolve(true);
  }

  canActivateChild(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<boolean> {
    return this.canActivate(route, state);
  }
}

Working code: https://stackblitz.com/edit/angular-route-guards-9tzxmv

Issue was because of this line:

switch (guardKey) {
  case GUARDS.GUARD1:
    guard = new Guard1(this._Router);   // because of this line it was creating issue
    break;
  case GUARDS.GUARD2:
    guard = new Guard2();
    break;
  default:
    break;
}
Sign up to request clarification or add additional context in comments.

Comments

1

As per the stackblitz code shared, the guard is defined as:

    let guard: Guard1 | Guard2;

So guard can be either of the type Guard1 or Guard2, and each of those classes have a different canActivate method return type. One has return type Observable<boolean>, while another has Promise<boolean> .

The return guard.canActivate(this.route, this.state); statement can either return Observable<boolean> or Promise<boolean>, whereas the function containing the return statement is defined to return Promise<boolean>.

Do you really need canActivate method of Guard1 and Guard2 class to have different return types? If you can keep the return type consistent, then that should resolve the issue.

In case if your requirement is still to have different return types, then in case when guard is assigned to Guard2 instance, the return statement should be as:

    return guard.canActivate(this.route, this.state).toPromise();

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.