-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Control flow analysis overriding an explicit type declaration when the type flows from optional chaining #50444
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
That the type of whatever you assign takes priority over the annotation is working as intended. However, I'm surprised why |
This is probably related to the fact that
If that's the case then OK - although I find it a little bit weird. As I've written down a manual annotation - I don't want to rely on inference here. |
Assignment narrows, that's the major point. It would be weird to assign a You can use a type assertion instead of an annotation, although that has some drawbacks too. You actually want #47920. |
I know that semantics of the This use case rly is not that important to ke though. I was just buffled when ive spotted this behavior as i didnt know about it (usually it doesnt matter so ive never noticed it). Adding on top of that the inconsistent behavior of ternary expressions i’ve thought that it is an actual bug |
The idea is that let x: number | string = "foo";
takesAString(x); should not behave differently from let x: number | string;
// maybe some other stuff here
x = "foo";
takesAString(x); // no type check needed, assigned on previous line |
I see them slightly differently - the middle step between the declaration and the call is IMHO important. With it, I can see that there is CFA applied after I set a boundary for the "input" (the manual annotation). It makes sense that TS takes new information into account - it makes less sense to me that it ignores my manual boundary. But overall, as mentioned - I don't intend to fight this, it's an acceptable situation for me, I just have been caught off guard here. I don't understand though why a type reported at the declaration matches my declared type but yet it's narrowed down just one line below that declaration. If this is expected behavior then IMHO they both should display the same. |
See the discussion in #50002. |
Hovering on a declaration name shows you the declared type. This is the type that doesn't have any CFA applied -- effectively it's telling you what the possible, all-worlds value of a value would be. Initialization does perform narrowing. Not doing this opens you up to stuff that just looks broken as heck; this used to not happen and everyone hated it. For a type SU = string | undefined;
// Forward reference is legal here and gets declared type
// Initialization of undefined is plainly legal by inspection -- `typeof a` is SU absent CFA info
const b: typeof a = undefined;
const a: SU = "hello";
a.charAt(0); // Should be legal by inspection - 'a' was clearly initialized There are a bunch of invariants you might want here and they can't all be simultaneously satisfied. |
This issue has been marked as 'Not a Defect' and has seen no recent activity. It has been automatically closed for house-keeping purposes. |
Bug Report
I'm not exactly sure if this is a bug or not - CFA rules are not well-documented. I find the present behavior to be quite annoying though
🔎 Search Terms
narrowing, control flow analysis, nullable, optional chaining
🕗 Version & Regression Information
🙁 Actual behavior
Referencing a variable with the declared type that originates in an expression using optional chaining doesn't include
| undefined
in its type.Note that
acquireVsCodeApi
is always defined according to the types.🙂 Expected behavior
Even though
acquireVsCodeApi
is always defined I would expect my explicit declaration on the assigned variable to win for the purpose of CFA.I have an app that is running as a standalone but it's also bundled as a VS Code extension. It's a hussle to include the VS Code types conditionally and it's much easier for us to just add those defs globally and refine this stuff at runtime when needed.
The text was updated successfully, but these errors were encountered: