Better type checking thanks to @let block

There are cases where checking the type of a variable in a template is necessary. The `@let` block from Angular 18 allows you to define a variable in a template and reuse it in many places. Thanks to that Type Narrowing finally works in Angular templates.

October 1, 2024 angularangular-18

Intro

@let block that allows you to define a variable in a template and reuse it in many places.

app.component.html
1
@let tasks = tasks$ | async;
2
3
@if(tasks === null) {
4
<p>Loading...</p>
5
} @else if(tasks.length > 0) {
6
<ul>
7
@for(let task of tasks) {
8
<li>{{ task.name }}</li>
9
}
10
</ul>
11
} @else {
12
<p>No tasks</p>
13
}

@let and Type Narrowing

The @let block can be used to narrow the type of a variable in a template. It is especially useful when you have a signals based application.

app.component.ts
1
type ComponentState =
2
| { status: "LOADING" }
3
| { status: "LOADED"; data: string[] }
4
| { status: "ERROR"; error: string };
5
6
@Component({ ... })
7
export class AppComponent {
8
const state = signal({ name: "PRISTINE" });
9
}
app.component.html
1
@let state = state();
2
3
@if(state.status === "LOADING") {
4
<p>Loading...</p>
5
} @else if(state.status === "LOADED") {
6
<ul>
7
<!-- state has type `{ status: "LOADED"; data: string[] }` -->
8
@for(let task of state.data) {
9
<li>{{ task }}</li>
10
}
11
</ul>
12
} @else {
13
<!-- state has type `{ status: "ERROR"; error: string }` -->
14
<p>{{ state.error }}</p>
15
}

To do the same with *ngIf, you would have to repeat the type check in each *ngIf block

1
@Component({ ... })
2
export class AppComponent {
3
state = signal({ name: "LOADING" });
4
5
isLoaded(state: ComponentState): { status: "LOADED"; data: string[] } | false {
6
return state.status === "LOADED" ? state : false;
7
}
8
}
1
<ng-container *ngIf="isLoaded(state()); as loadedState">
2
<ul>
3
<!-- loadedState has type `{ status: "LOADED"; data: string[] }` -->
4
@for(let task of loadedState.data) {
5
<li>{{ task }}</li>
6
}
7
</ul>
8
</ng-container>

Source

Do you like the content?

Your support helps me continue my work. Please consider making a donation.

Donations are accepted through PayPal or Stripe. You do not need a account to donate. All major credit cards are accepted.

Leave a comment