-
Notifications
You must be signed in to change notification settings - Fork 12.8k
T | U var with initial type T, set to a U inside lambda always deduced as T #10613
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
The issue is the compiler has no idea when the function will be called. in this case |
i suppose this is a regression from #8548 |
Not sure if this could be applied to TS, but Swift supports the func example(@noescape lamb: () -> ()) {
lamb()
} The compiler then checks that Downsides: all of the standard library methods would have to be annotated and for it to work for me as well I would have to annotate it as well, but the only other option is cross-module SA (which is also impossible for any native functions) |
To follow up on mhegazy's first comment: Indeed, the compiler right now has no way of knowing what will happen, but it pretends it knows anyway by assuming the lambda will not be called directly. If it truly cannot know, it has to leave the type alone and have the programmer do any manual casts, etc. |
After looking into it more, and catching up on changes in the last month or so, the reversal of the behavior in #8548 is intentional. see #10118 for more details. My comment earlier still holds. the compiler does not check lambdas, or any calls for possible side effects. it can not make an assumption about the lambda being called immediately or not. Consider the same example with var curThing: { x: number } | null = null;
lines.forEach(changeValueOfcurThing)
if (curThing) {
console.info(curThing.x);
}
function changeValueOfcurThing {
curThing = {x:1}
} To get this right, first every call site has to be investigated for possible side effects, the annotation on the function declaration should be consulted, and the control flow analysis should be done on the function body as if it was inlined at the call site, then conclude that All of this is theoretically doable; but doing this would drastically increase the compilation time and the complexity of the compiler. The workarounds available now, is using the bang if (curThing) {
console.info(curThing!.x); // trust me curThing is not null
} use a cast for function test(lines: string[]) {
var curThing: { x: number } = <any> null;
// i am sure it will be set to a non-null value later on
lines.forEach(line => {
curThing = { x: 1 };
});
if (curThing) {
console.info(curThing.x);
}
} |
Fair enough. I realised this would be a tricky one but figured I'd put it up. Thanks for giving it consideration. |
Uh oh!
There was an error while loading. Please reload this page.
TypeScript Version: 2.0.2 (RC)
Code
Expected behavior:
No errors.
Actual behavior:
When strict null checks are on, TS2 RC deduces that
curThing
in theif
at the end is of typenull
and inside the block is of typenever
. The error I get then is thatnever
has no member named x. Fair enough.In this case I can sidestep the issue by using
for (var line of lines) { … }
instead of the forEach method, but that may not always be the case. BTW, this is a reduced case from some parser code.This case also deals with
T | null
but this applies to anyT | U
type value. I tested this separately with astring | number
initialised to a number and then set to a string, etc.The text was updated successfully, but these errors were encountered: