Repository navigation
Description
🐞 bug report
Affected Package
The issue is caused by package @angular/compiler (I guess)
Is this a regression?
Yes, kiiiiinda
With enableIvy false (v9 and I'm almost certain v8 as well), changing the final non-null assert (!) in the template into a null propagation (?) makes the error go away.
Description
The code in the reproduction below compiles with "strictTemplate": true in tsconfig, but not with "fullTemplateTypeCheck": true only.
As far as I understand, anything that compiles with strict should compile with full? As an aside, I think it would be good if that was made clear one way or another in this section of the docs (happy to raise a separate issue).
Furthermore, the error in full mode doesn't make any sense, as far as I understand.
As noted above, there is a similar issue with Ivy disabled, but for reasons I don't understand it goes away when using null propagation rather than non-null assertion.
🔬 Minimal Reproduction
https://github.com/jgbpercy/AngularCompilesOnlyStrict
(currently the repo should be in a non-compiling state - add "strictTemplate": true to tsconfig angularCompilerOptions and it should compile)
🔥 Exception or Error
ERROR in src/app/app.component.html:2:12 - error TS2339: Property 'doDar' does not exist on type 'never'.
2 {{ (thinger!.innerObs | async)!.doDar }}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/app/app.component.ts:14:16
14 templateUrl: './app.component.html',
~~~~~~~~~~~~~~~~~~~~~~
Error occurs in the template of component AppComponent.
🌍 Your Environment
Angular Version:
Angular CLI: 9.0.3
Node: 10.15.0
OS: win32 x64
Angular: 9.0.2
... animations, common, compiler, compiler-cli, core, forms
... language-service, platform-browser, platform-browser-dynamic
... router
Ivy Workspace: Yes
Package Version
-----------------------------------------------------------
@angular-devkit/architect 0.900.3
@angular-devkit/build-angular 0.900.3
@angular-devkit/build-optimizer 0.900.3
@angular-devkit/build-webpack 0.900.3
@angular-devkit/core 9.0.3
@angular-devkit/schematics 9.0.3
@angular/cli 9.0.3
@ngtools/webpack 9.0.3
@schematics/angular 9.0.3
@schematics/update 0.900.3
rxjs 6.5.4
typescript 3.7.5
webpack 4.41.2
Anything else relevant?
The language service thinks the code is fine and picks up the type ok!
So I'm guessing in full the first | async is polluting the type it outputs with a union to null, and then the second | async is chewing up horribly on that somehow. Whereas in strict it has enough information to know that null isn't part of the relevant type at the right time.
Activity
JoostK commentedon Feb 24, 2020
I think what's going in here is that with only
fullTemplateTypeCheckset, thestrictInputTypesoption is disabled so the type ofthingeris inferred asany. Theasyncpipe has various overloads for itstransformmethod, the first one being:Therefore, the type of
(thinger!.innerObs | async)is inferred asnullgiven that this first overload matches theanytype that is passed in. The non-null operator will then "remove"nullandundefinedfrom the type, and removingnullfromnullis equal to the typenever.I am not quite sure why using the
?does not have the same behavior, I'd have to look into that more.This can probably be fixed using a different overload overing in the
asyncpipe'stransformdeclaration.alxhub commentedon Feb 26, 2020
I don't know if going through a different overload is going to help.
I reordered them here and played around with the inference: http://www.typescriptlang.org/play/#code/CYUwxgNghgTiAEkoGdnwPICNkhgNykwhAB4AVAPngG94BfAKAaVXgEFkBPAOzAAUAlgAcE1JvHgAXGFG7IAZgHsYAW3IUAFIswArAFwZsuAkVKUAPtwCuECOavdQ8gdxDAAlAbKWbEANwMEtKyCspqlFq6BnwwiioCOOo+tvaOIM6uHl7J-oFSMnJKquqR+vDWtp7lvgFBBaHFEdplDk4ublWt6e3AtRL5IUUqpQZYOPiExCSynFTm8DFxCaQzc9W28PNdGR0GMzR5EoyMzIpykvBC8AC85SAA7uxcvIIiGu4BoEhwiGfIFwAPPbcTgBMB-C5wNC3IQAOmChTCGgBH3gAHo0fAHABrbiKe7cIA
However, even if we go through the
Observable<T>branch, what ends up happening is that TypeScript tries to solveObservable<T> = anyforT, and since it has no context for inferringTin this case, it defaults tounknown, which is only slightly better thanneverand not at all helpful to this case -doDaris no more present onunknownthannever.The only way I could make this work is with magic type hacks:
This adds an overload signature to
AsyncPipe.transformspecifically for the case where someone passesany.jgbpercy commentedon Feb 26, 2020
Thanks both for the interesting explanations! So the problem is you want an overload to match
any, but onlyany...Just to be clear, talking about our code specifically, we'll be using
strictTemplatefor Ivy, and in our library code that is still (for now) non-Ivy compiled, we can drop back to the null propagation workaround that works whenenableIvyis false. So this isn't something that's actively a problem for us I don't think. I'm personally fine with this being closed as not worth fixing, but I'll leave it up to you.alxhub commentedon Feb 26, 2020
I think it's worth fixing, for sure.