question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. ItΒ collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Compile errors when using async pipe with enableIvy & strictNullChecks

See original GitHub issue

🐞 bug report

Affected Package

@angular/compiler-cli, @angular/angular

Is this a regression?

Yes, this works when Ivy is not used.

Description

The problem is the async pipe returns T | null. My understand is Ivy uses code similar to Partial<Pick<ChildComponent, β€˜prop’>> to check property bindings in templates. That allows undefined, but not null. Similarly, ngForOf doesn’t allow null, so that also doesn’t work with async.

This causes templates that previously compiled without errors to fail.

    <!-- Must be built with strictNullChecks && enableIvy to see the errors below -->
    <ul>
      <!-- Type 'string[] | null' is not assignable to type 'string[] | Iterable<string> | undefined' -->
      <li *ngFor="let n of array$ | async">{{n}}</li>
    </ul>
    <!-- Type 'number | null' is not assignable to type 'number | undefined' -->
    <app-child [prop]="value$ | async"></app-child>

We use ngrx/store, so we use the async pipe a lot, and for the most part the observables from the store will always return a value immediately. But async’s return type means we have to deal with the null somehow even if it will never be emitted.

I’ve come up with several workarounds, but I don’t like any of them very much. And even if this is seen as behaving as intended, documentation should be updated (e.g. the example in https://angular.io/api/common/NgForOf#local-variables wouldn’t work with strictNullChecks && enableIvy).

Workarounds:

  1. Using non null assertions [prop]=(value$ | async)!"

I don’t like this since I don’t want developers to get used to throwing it around causally.

  1. Use || to provide a default, *ngFor=β€œlet i of (array$ | async) || []”

This works okay for the ngFor case, but doesn’t work for the prop case if one of the valid values is falsey, or if there is no good default value.

  1. Use ngIf with async, *ngIf=β€œvalue$ | async as value”

This is probably a good choice for the cases where the async pipe would legitimately be null, but is just needlessly cluttering template with ng-contianer or other elements in the cases where the async pipe will never return null. It also doesn’t work when the pipe will return a falsey value.

  1. Create a β€œpresent” pipe that throws if it’s input is null/undefined and converts T | null to just T

Alternatively create a currentValue pipe that combines async & present, which could limit the input to Observable<T> (since the other options would just cause it to throw anyway).

This works but it makes the template expressions longer, and if it’s not built into @angular/angular its more for new devs on the team to understand.

πŸ”¬ Minimal Reproduction

I’ve created a repo showing this issue: https://github.com/james-schwartzkopf/test-template/blob/master/src/app/app.component.ts

πŸ”₯ Exception or Error

See Above

🌍 Your Environment

Angular Version:


$ ng --version

     _                      _                 ____ _     ___
    / \   _ __   __ _ _   _| | __ _ _ __     / ___| |   |_ _|
   / β–³ \ | '_ \ / _` | | | | |/ _` | '__|   | |   | |    | |
  / ___ \| | | | (_| | |_| | | (_| | |      | |___| |___ | |
 /_/   \_\_| |_|\__, |\__,_|_|\__,_|_|       \____|_____|___|
                |___/
    

Angular CLI: 8.2.0
Node: 10.15.1
OS: win32 x64
Angular: 8.2.0
... animations, cli, common, compiler, compiler-cli, core, forms
... language-service, platform-browser, platform-browser-dynamic
... router

Package                           Version
-----------------------------------------------------------
@angular-devkit/architect         0.802.0
@angular-devkit/build-angular     0.802.0
@angular-devkit/build-optimizer   0.802.0
@angular-devkit/build-webpack     0.802.0
@angular-devkit/core              8.2.0
@angular-devkit/schematics        8.2.0
@ngtools/webpack                  8.2.0
@schematics/angular               8.2.0
@schematics/update                0.802.0
rxjs                              6.4.0
typescript                        3.5.3
webpack                           4.38.0

Anything else relevant?


$ cat ./tsconfig.app.json
{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "outDir": "./out-tsc/app",
    "types": []
  },
  "files": [
    "src/main.ts",
    "src/polyfills.ts"
  ],
  "include": [
    "src/**/*.d.ts"
  ],
  "angularCompilerOptions": {
    "enableIvy": true
  }
}


$ cat ./tsconfig.json
{
  "compileOnSave": false,
  "compilerOptions": {
    "strictNullChecks": true,
    "baseUrl": "./",
    "outDir": "./dist/out-tsc",
    "sourceMap": true,
    "declaration": false,
    "downlevelIteration": true,
    "experimentalDecorators": true,
    "module": "esnext",
    "moduleResolution": "node",
    "importHelpers": true,
    "target": "es2015",
    "typeRoots": [
      "node_modules/@types"
    ],
    "lib": [
      "es2018",
      "dom"
    ]
  },
  "angularCompilerOptions": {
    "fullTemplateTypeCheck": true,
    "strictInjectionParameters": true
  }
}

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Reactions:12
  • Comments:17 (11 by maintainers)

github_iconTop GitHub Comments

4reactions
JoostKcommented, Oct 18, 2019

@klemenoslaj Ivy’s template type checker is far more advanced than the level of type checking that was previously done for templates, and in general the errors it produces are accurate. The problem is that they may be too accurate for someone’s liking, especially because of cases like ngFor together with the async pipe where there has always been a type mismatch that has not been surfaced before because the type checking was not as accurate as it is becoming now.

Is it now expected that all inputs in our applications accept null?

This is not the case. This issue in particular is about the async pipe, which includes null in its return type as it can’t differentiate based on the type of Observable if it will emit synchronously, or whether there may be a gap between the time of subscribing and the first value emission (in which case the async pipe has to return null, because it doesn’t have any other information)

The good news is that we recently introduced an internal template type checking option to effectively ignore typing issues around null and undefined. A public facing option will be added shortly, so that developers can disable certain areas of the template type checker. This is basically @pshurygin’s suggestion in https://github.com/angular/angular/issues/32051#issuecomment-536285449.

Disclaimer: I am not entitled to make official statements πŸ˜ƒ I’m just enthusiastic about Ivy and helping out whenever I can.

1reaction
james-schwartzkopfcommented, Oct 11, 2019

So only ngFor was changed? This will still be an issue for @Inputs that don’t include null in their type?

Read more comments on GitHub >

github_iconTop Results From Across the Web

angular and async pipe typescript complains for null
In this example, the compiler disregards type incompatibilities in nullability, just as in TypeScript code. In the case of the async pipe,Β ...
Read more >
Pains with Ivy, Async Pipe and strictNullChecks : r/Angular2
So I'm upgrading our library/sample-app to use Angular 8. I decided to go ahead and try to enable Ivy while I was at...
Read more >
Type-checking templates in Angular ViewEngine and Ivy
If we try to build this component in AOT mode we'll get the error ... It's helpful when we use β€œstrictNullChecks”: true in...
Read more >
Angular Async Pipe – How to Handle Errors - Coding Latte
In this post, I am going to show you a very simple yet effective way of handling errors when using Async Pipe in...
Read more >
Angular V9 Async Pipe Not Updating Template View On Data ...
We use ngrx/store, so we use the async pipe a lot, and for the most Must be built with strictNullChecks && enableIvy to...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found