-
Notifications
You must be signed in to change notification settings - Fork 13.2k
Open
Labels
BugA bug in TypeScriptA bug in TypeScriptDomain: check: Control FlowThe issue relates to control flow analysisThe issue relates to control flow analysisHelp WantedYou can do thisYou can do this
Milestone
Description
Bug Report
🔎 Search Terms
- type revert
- type for loop wrong
- type narrowing loop
🕗 Version & Regression Information
Happens in versions 3.3.3333 to 4.8.0-dev.20220613 (latest nightly). I couldn't test prior versions as that's the oldest the playground will go.
⏯ Playground Link
💻 Code
interface XMLNode {
}
// Other functions have the same signature, but it is not needed to replicate this issue
function accessArray(node:XMLNode, createIfNotExists:true):XMLNode;
function accessArray(node:XMLNode, createIfNotExists:boolean):XMLNode|undefined;
function accessArray(node:XMLNode, createIfNotExists:boolean = false):XMLNode|undefined {
return undefined;
}
function accessCatalogEntry(createIfNotExists:boolean):XMLNode|undefined {
return undefined;
}
function accessFieldValue(createIfNotExists:boolean):XMLNode|undefined {
let cur = accessCatalogEntry(createIfNotExists);
if(!cur){
return undefined;
}
// At this point, cur is XMLNode
for(let i = 0; i < 5; ++i){
// But here, cur is XMLNode|undefined
let tmp = accessArray(cur, createIfNotExists);
// Declaring the type of tmp to be XMLNode|undefined, fixes this issue
if(!tmp){
return undefined;
}
cur = tmp; // This line is what's confusing the compiler
}
return cur;
}🙁 Actual behavior
The compiler forgets that cur can only be XMLNode inside the loop. It prints an error on the line with the call to accessArray since it thinks cur might be undefined
🙂 Expected behavior
It is provably that its value will always be XMLNode, since once the loop is entered, cur is XMLNode, and the only assignment to it comes from a variable that is narrowed to also be XMLNode.
To be frank, the logic seems a bit circular and hard to analyze from the compiler perspective. Removing the cur = tmp; is enough to remove the type error, for example.
Changing the code to this is also enough to let the compiler type check properly:
function accessFieldValue_workaround1(createIfNotExists:boolean):XMLNode|undefined {
let cur_ = accessCatalogEntry(createIfNotExists);
if(!cur_){
return undefined;
}
// At this point, cur_ is XMLNode
// This line will enforce the typecheck to know the type is XMLNode inside the loop too
let cur = cur_;
for(let i = 0; i < 5; ++i){
let tmp = accessArray(cur, createIfNotExists);
if(!tmp){
return undefined;
}
cur = tmp;
}
return cur;
}Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
BugA bug in TypeScriptA bug in TypeScriptDomain: check: Control FlowThe issue relates to control flow analysisThe issue relates to control flow analysisHelp WantedYou can do thisYou can do this