TypeScript
TypeScript copied to clipboard
Truthy value not recognized by CFA as a constant condition in loops
Bug Report
🔎 Search Terms
while loop, infinite, cfa, control flow analysis
🕗 Version & Regression Information
This is also the 'Nightly' version in the playground: nightly TS playground
- This is the behavior in every version I tried
⏯ Playground Link
Playground link with relevant code
💻 Code
type DigraphNode = {
data: {
key: string;
};
parent?: DigraphNode;
};
export function getStringPath(node: DigraphNode): string[] { // Function lacks ending return statement and return type does not include 'undefined'.(2366)
let currentNode: DigraphNode = node;
const path = [];
while (currentNode) {
// do not include root's key
if (!currentNode.parent) {
return path.reverse();
}
path.push(currentNode.data.key);
currentNode = currentNode.parent;
}
}
🙁 Actual behavior
I get an error:
Function lacks ending return statement and return type does not include 'undefined'.(2366)
🙂 Expected behavior
I shouldn't get an error because currentNode is always truthy, this should work in the same way as while (true) (TS playground).
Interesting case. Right now this check is almost entirely syntactic; it does consider exhaustive switches but otherwise doesn't use CFA types at all.
This is probably a Won't Fix unless the fix is extremely cheap, since the logic of "this is the same as a while (true)" strongly implies that the program should just be written that way.
Wouldn’t it just be the same check as the one that produces “this condition will always be true because…” diagnostics for if statements?
This is probably a Won't Fix unless the fix is extremely cheap, since the logic of "this is the same as a while (true)" strongly implies that the program should just be written that way.
I agree that this is how it should be written and I've rewritten it this way before opening this issue. However, I think that the compiler shouldn't rely on this - that's why I've created an issue. A diagnostic like the one mentioned by @fatcerberus would also be nice but not necessary.
Wouldn’t it just be the same check as the one that produces “this condition will always be true because…” diagnostics for if statements?
Interestingly, this particular situation doesn't produce such a diagnostic even with the if statement and it suffers from the same issue related to the return type:
type DigraphNode = {
data: {
key: string;
};
parent?: DigraphNode;
};
export function getStringPath(node: DigraphNode): string[] { // Function lacks ending return statement and return type does not include 'undefined'.(2366)
let currentNode: DigraphNode = node;
const path = [];
if (currentNode) {
path.push(currentNode.data.key);
return path.reverse();
}
}