You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
strictNullChecks mode - variable initial value is ignored in the control flow #10640
interfaceIFoo{foo?: string;};vara: IFoo={foo: ''};a.foo.split('');// <-- Error: a.foo is possibly undefined!
Expected behavior:
This is a valid piece of code. a.foo is defined, therefore, a.foo.split is a valid expression.
Actual behavior:
a.foo is concluded as type string | defined, even though it is defined in the initiation phase var a:IFoo = { foo: '' }. tslint/typescript complains that foo is possibly undefined and therefore, cannot access to split method.
the following code runs without problem simply because foo is assigned after a declaration:
{ foo: '' } is assignable to IFoo. so the type of a becomes IFoo. in the second code you're assigning something to a.foo and the control flow analyzer can prove that a.foo has value. I understand what you're asking the type-checker is valid, but it's way too far fetched!
I don't know if I've managed to explain the problem clearly. I'll elaborate :)
The first code snippet doesn't work and that's the bug I am writing about. a.foo is initialized as a string and not a string|undefined. The linter fails to recognize that there is a initial value for a. And therefore, I cannot call split method on a.foo because it thinks that it is string|undefined.
let a = { foo: '' };
a.foo.split(''); // <-- no error
The reason for adding the explicit type annotation is because you are planning to assign to a objects that may or may not have a foo property. Therefore code such as a.foo.split does need to be protected against that possibility. In future maintenance it might move away from its current position and get a line inserted before it that changes a. The compiler is being helpful based on what you've told it.
If you don't want the help, don't ask for it! :) (just remove the type annotation from a).
Daniel Earwicker (@danielearwicker) yes for the example I provided it may look silly to annotate the type :) But, this is just a simplified example to show the bug, not the necessity. The use case of this can vary of course:
This is not the code I encountered this problem with since it is out of topic here. But it is a close example to the real case. The point being, the compiler doesn't take the initialization phase of the variable into account to not infer object|undefined type in strictNullCheck mode.
We only narrow unions. the type of a is not, it is an IFoo. so a is not narrowed. so perhaps we need to consider property declarations as if they were assignments, i.e. treat it as:
There are some technical challenges here that would make this rather expensive in our current design. We'll think about it more and see if there's something that can be done, but there isn't an obvious solution at this time.
Activity
alitaheri commentedon Aug 31, 2016
{ foo: '' }is assignable toIFoo. so the type of a becomesIFoo. in the second code you're assigning something toa.fooand the control flow analyzer can prove thata.foohas value. I understand what you're asking the type-checker is valid, but it's way too far fetched!Embrace for
By DesignorWorking as Intended😅aliai commentedon Aug 31, 2016
I don't know if I've managed to explain the problem clearly. I'll elaborate :)
The first code snippet doesn't work and that's the bug I am writing about.
a.foois initialized as a string and not a string|undefined. The linter fails to recognize that there is a initial value fora. And therefore, I cannot callsplitmethod ona.foobecause it thinks that it is string|undefined.The code fails on the last line
a.foo.split('')HerringtonDarkholme commentedon Aug 31, 2016
Ali Taheri Moghaddar (@alitaheri) This snippet might help illustrate the problem.
alitaheri commentedon Aug 31, 2016
Ali Arafati (@aliai) Herrington Darkholme (@HerringtonDarkholme) I did get the problem. It's just that I thought maybe the cast to IFoo erases the information about
foo.Interestingly, this code doesn't work either:
This sure does look like a bug to me 😅
danielearwicker commentedon Sep 2, 2016
Naturally this works fine (inferred type of
a):The reason for adding the explicit type annotation is because you are planning to assign to
aobjects that may or may not have afooproperty. Therefore code such asa.foo.splitdoes need to be protected against that possibility. In future maintenance it might move away from its current position and get a line inserted before it that changesa. The compiler is being helpful based on what you've told it.If you don't want the help, don't ask for it! :) (just remove the type annotation from
a).aliai commentedon Sep 2, 2016
Daniel Earwicker (@danielearwicker) yes for the example I provided it may look silly to annotate the type :) But, this is just a simplified example to show the bug, not the necessity. The use case of this can vary of course:
This is not the code I encountered this problem with since it is out of topic here. But it is a close example to the real case. The point being, the compiler doesn't take the initialization phase of the variable into account to not infer
object|undefinedtype in strictNullCheck mode.mhegazy commentedon Sep 21, 2016
We only narrow unions. the type of
ais not, it is anIFoo. soais not narrowed. so perhaps we need to consider property declarations as if they were assignments, i.e. treat it as:RyanCavanaugh commentedon Sep 28, 2016
There are some technical challenges here that would make this rather expensive in our current design. We'll think about it more and see if there's something that can be done, but there isn't an obvious solution at this time.