If you’ve worked with Angular apps, chances are you’ve used the ngIf directive. ngIf lets you conditionally render a template based on the result or an expression; if the expression is truthy, the template is rendered. If it’s falsy, template is not rendered. While this is all pretty straightforward, I ran into a quirky issue just the other day while using this simple directive on a Typescript project with AoT compilation.

I was using ngIf in one of my html template files as below :

<div *ngIf=”!isLoading && user” >

If you’re wondering what I’m doing here, assume I am displaying information about a user on the screen. Before displaying this info, I’m simply checking if app loading has finished and users’ data is available. The variables used in the expression are defined in the accompanying component .ts file :

public isLoading: boolean;

public user: User;

Now this is all really simple. Under JIT compilation, the app would compile without errors. But wait till we compile it using Angulars’ Ahead Of Time (AoT) compiler. It will throw an error similar to the one below.

app.html (1,5) : Type ‘User’ is not assignable to type ‘boolean’.

What’s happening here?

When the AoT compiler runs, it converts the html template into a typescript class (.ts) file. And the code representing the ngIf expression would be generated :

const currVal_5:boolean = (!this.context. isLoading && this.context.user);

Typescript will now try to evaluate this expression. The first operand returns a boolean and poses no issue. However, the second operand does not return a boolean but a truthy or falsy value, as the user instance resolves to a value of type User. Now typescript will resolve the type of the entire expression to be of type User since it was the type of the last operand in the expression. This triggers the “User’ is not assignable to type ‘boolean” error.

How do we resolve it?

There are multiple approaches we can take to resolve this issue. Pick the best approach that suits your design. Ultimately the trick is to make the expression evaluate to a proper boolean value.

Change the order of the operands so the expression resolves to a boolean value

We can re order the ngIf statement so that the last operand returns a boolean :

<div *ngIf=”user && !isLoading” >

This will now be generated by the AoT compiler as below:

const currVal_5:boolean = (this.context.user && !this.context. isLoading );

Since the type of the last operand is now a boolean, the auto generated expression will now resolve into a boolean.

Cast truthy values into booleans using the !! operator

<div *ngIf=”!isLoading && !!user” >

By using !!user syntax, we will always be casting the truthy or falsy value of user instance into a boolean, thus making the entire expression resolve to a boolean value.

Move the logic to a function in the accompanying component

Alternatively, we can move the logic of the ngIf expression into a function that returns a boolean which resides in the component. This is recommended when the logic used in the ngIf is complex.

<div *ngIf=”isUserLoaded()” >

And the component function will look similar to:

public isUserLoaded(): boolean { return ( this.user && !this.isLoading ); }

An added advantage of this method is that you can identify and avoid bugs caused by type mismatches even during JIT compilation. The typescript compiler will immediately throw the type mismatch error as it goes through the function in component .ts file.

Why does this error pop up only during AoT compilation?

During JIT compilation, the typescript compiler (tsc) will not convert the template into a .ts file. Thus it will not check the ngIf expressions in the template at all during compilation; they are pretty much ignored. However the AoT compiler will convert the html into a typescript class. And it will type check the expressions during compile time and throw the the error.