NG hint [type narrowing with built-in control flow]

Wojciech Trawiński
JavaScript everyday
3 min readDec 3, 2023

Angular 17 has introduced the built-in control flow to its templates. Amongst its great number of advantages, there is one that may be overlooked, namely improved type narrowing. Let’s explore!

if / else statement

Let’s consider the following union type:

TypeScript employs the concept of discriminated unions which allows for proper type narrowing, namely:

Note that the analysisState type is properly narrowed within the else branch, therefore it is safe to access the result property.

Let’s see how type narrowing is performed in Angular templates.

NgIf directive (old approach)

Unfortunately, the NgIf directive is not capable of performing type narrowing within the else template:

In general, it even makes sense, since the else template can be used by other NgIf directives within the template.

A quick solution is to cast the analysisState to any type:

However, a better solution, when it comes to type safety, is to use another if condition, since the NgIf directive properly narrows type within its template:

Summing up, when using the NgIf directive, type narrowing does not work as glitch-free as it should as compared to the plain TypeScript example.

if / else blocks (new approach)

Fortunately, using the new built-in control flow all the aforementioned challenges are not an issue, since type narrowing works in the same manner as in the plain TypeScript example:

switch statement

Let’s continue with the example from the previous section.

An alternative plain TypeScript solution relying on the switch statement looks as follows:

Once again, the analysisState type is properly narrowed, hence the result property can be accessed within the second case block.

Let’s now focus on Angular templates.

NgSwitch directive (old approach)

Unfortunately, no type narrowing happens for any execution branch:

In order to compile the code, casting to any type is required:

Similar to the NgIf directive, the NgSwitch directive lacks the ability to perform type narrowing.

switch / case blocks (new approach)

The new built-in control flow ensures type narrowing in Angular templates for switch statements as well:

If you like the hint, please give me some applause 👏

--

--