Encountering an issue with Angular: The type 'boolean | Observable<boolean>' cannot be assigned to the type 'boolean'

Check out this answer to understand the approach I am using for implementing the master guard. I have multiple guards that need to be executed in sequence.

In Master Guard -

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

The complete function is outlined below:

//Instantiate the guard and call 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 encountered the following error:

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

You can find the stackblitz link here

Shared screenshot: https://i.sstatic.net/CskTp.png I would appreciate any help or solutions to resolve this error. Thank you!

Answer №1

After examining your problem, I have identified that guard1 service and guard2 service have different return types. They both need to have a return type of Promise<boolean> as specified in the MasterGuard service code.

If you take a look at activateGuard() in the MasterGuard service, it is expecting a return of Promise<boolean>. However, in guard1 service, you are returning 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);
  }
}

Here is the link to the working code demonstrating the correct implementation: https://stackblitz.com/edit/angular-route-guards-9tzxmv

The issue was caused by the following 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;
}

Answer №2

Upon reviewing the stackblitz code provided, it is evident that the guard variable is declared as:

    let guard: Guard1 | Guard2;

This signifies that `guard` can be of either type Guard1 or Guard2, with each class having a distinct return type for the canActivate method. One class returns Observable<boolean>, while the other returns Promise<boolean>.

The issue arises when the statement

return guard.canActivate(this.route, this.state);
can potentially return either an Observable<boolean> or a Promise<boolean>, despite the function being defined to only return a Promise<boolean>.

If maintaining consistent return types is feasible, it is recommended to do so in order to resolve this discrepancy. However, if differing return types are necessary, then when assigning the guard to an instance of Guard2, the return statement should be modified to:

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

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Clear drop down selections after button is pressed

I am currently working with a grid in my template that contains multiple dropdowns, each row having its own. When I click a button, I gather the values from these dropdowns. However, upon clicking this button, I wish to reset all the dropdowns back to thei ...

Instead of the type definition file, navigate to the TypeScript source file within VS Code

A unique npm library I developed is utilized in various main projects, with all the sources stored within a /src directory and written in TypeScript. The compiler options listed in the tsconfig.json file include "sourceMap": true and "outDir": "dist". Addi ...

Is there a way to configure ESLint so that it strictly enforces either all imports to be on separate lines or all on a single line?

I am currently using ESLint for TypeScript linting. I want to set up ESLint in a way that requires imports to be either all on separate lines or all on a single line. Example of what is not allowed: import { a, b, c, d } from "letters"; Allo ...

Error with Angular InjectionToken utilization

We are encountering an issue while trying to inject a value using InjectionToken. The error message that we are receiving is as follows: ERROR in Error encountered resolving symbol values statically. Only initialized variables and constants ...

Experiencing problems with the Locale setting when utilizing the formatNumber function in Angular's core functionalities

I am having trouble formatting a number in Angular using the formatNumber function from the Angular documentation. Here is my code snippet: import {formatNumber} from '@angular/common'; var testNumber = 123456.23; var x = formatNumber(Numb ...

Extract the array structure from the resolved promises using await with Promise.all()

When I receive the values returned by using await Promise.all() in the following manner: const [apple, banana] = await Promise.all<Object, Object>([ applePromise(), bananaPromise() ]).catch(error => next(error)); An error is triggered: T ...

Contrast between SimpleChange and SimpleChanges

I'm confused about the two terms in Angular 5, SimpleChange and SimpleChanges. Can someone please help explain them to me more clearly than what's in the official documentation? ...

When trying to access a property in Typescript that may not exist on the object

Imagine having some data in JS like this example const obj = { // 'c' property should never be present a: 1, b: 2, } const keys = ['a', 'b', 'c'] // always contains 'a', 'b', or 'c' ...

Ways to verify the compatibility between TypeScript type definitions in @types and the corresponding package

After dabbling with typescript in my node.js projects for a while, I've come to realize that many npm packages have separate @types packages for typescript definitions. But here's the dilemma: how can one be certain that the @types package is syn ...

Effortless JSON parsing with Angular 2 Http GET request

After sending an HTTP get request to my server API, I am attempting to parse the JSON object that is returned. Below is the code snippet for the Http call: getPayoutReport(param1, param2, param3) { //perform necessary actions //set up a requestUr ...

Issue with angular 8 radio button not being selected

Here is the HTML code I am working with: <div *ngFor="let option of systemEquipmentGroup"> <h5>{{option.optionGroupName}}</h5> <div> <label style="display: block;" * ...

Using Angular, we can make an HTTP call and map the response to an

I have a function that fetches information from a REST API in this format: getProducts(category: string): Observable<IProduct[]> { let url = `/rest/getproducts?category=${category}`; return this._http.get<IProduct[]>(url); } The dat ...

Using the mat-icon within several mat-select components

How can I resolve the issue with displaying mat-icon in a mat-select(multiple) field? After adding a mat-icon and selecting an option, the mat-icon value also appears in the selected values. Please see the attached images for reference: mat-select-list s ...

I am working in Angular 13 and attempting to dynamically assign attributes to an SVG HTML element by passing in values from variables declared in a TypeScript file

Within a specific HTML file of my Angular13 app, I'm aiming to dynamically bind a list of attributes and their values to an element using Angular's double-binding approach {{attribute value}}. This will allow me to display a series of social medi ...

Replace Formik with useFormik to streamline your code

I have implemented Formik/Yup for validation on a page that triggers a GraphQL mutation. The code is functioning as expected: export default function RemoveUserPage() { const [isSubmitted, setIsSubmitted] = useState(false); const [isRemoved ,setIsRemo ...

Enhance tns-platform-declarations with NativeScript

I am working on a NativeScript project and I am trying to incorporate the RecyclerView from Android Support Library. I have added the dependency in the app/App_Resources/Android/app.gradle file: // Uncomment to add recyclerview-v7 dependency dependencies ...

Can a specific type be created for a nested object that has varying levels of depth?

One of my functions organizes objects based on the length of an input array. For example: fn(['a']) -> Record<string, string> fn(['a', 'b']) -> Record<Record<string, string>> I've defined the ret ...

custom field component for react-hook-form

I have been working on creating a form field component that can be utilized at both the root form level and as a nested field. export type FirstNameField = { firstName: string; }; type GenericFormType<T, NS extends string | never = never> = NS ext ...

Can we securely retrieve nested properties from an object using an array of keys in TypeScript? Is there a method to accomplish this in a manner that is type-safe and easily combinable?

I wish to create a function that retrieves a value from an object using an array of property keys. Here's an example implementation: function getValue<O, K extends ObjKeys<O>>(obj: O, keys: K): ObjVal<O,K> { let out = obj; for (c ...

Sorting by the date column in Ngx-Datatable is malfunctioning

Below is the code I am currently working with: <ngx-datatable class="material" [rows]="rows" [columnMode]="'force'" [headerHeight]="50" [footerHeight]="50" [sorts]="[{prop: 'name', dir: 'desc'}]" [limit]="3"> ...