-
Notifications
You must be signed in to change notification settings - Fork 12.6k
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
Incorrect circularity detection #33191
Comments
here's another example from zone (source file function shallowObj(obj: {[k: string]: any} | undefined, depth: number): any {
if (!obj || !depth) return null;
const out: {[k: string]: any} = {};
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
let value: any = obj[key];
switch (typeof value) {
case 'object':
const name = value && value.constructor && (<any>value.constructor).name;
value = name == (<any>Object).name ? shallowObj(value, depth - 1) : name;
break;
case 'function':
value = value.name || undefined;
break;
}
out[key] = value;
}
}
return out;
} Gives:
|
Another example i've just come across, TypeScript version 2.8.3: function testFunction() {
let state: { value: number } | null = null;
for (let i = 0; i < 10; i++) {
const previousState = state;
// ^^^^^^^^^^^^^ error: 'previousState' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer.ts(7022)
state = null;
const value = i === 0 ? 0 : previousState?.value;
// ^^^^^ error: 'value' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer.ts(7022)
if (value !== undefined) {
state = { value: value + 1 }
}
}
console.log('Test Function:', state?.value);
} When putting in explicit type annotations, it produces a new error: function testFunction() {
let state: { value: number } | null = null;
for (let i = 0; i < 10; i++) {
const previousState: { value: number } | null = state;
state = null;
const value: number | undefined = i === 0 ? 0 : previousState?.value;
// Property 'value' does not exist on type 'never'.ts(2339): ^^^^^
if (value !== undefined) {
state = { value: value + 1 }
}
}
console.log('Test Function:', state?.value);
} |
Here's another case, but then with a interface Node {
next: Node | null;
}
function test(node: Node) {
let currentNode: Node | null = node;
while (currentNode !== null) {
const nextNode = currentNode.next;
// ~~~~~~~~ error TS7022: 'nextNode' implicitly has type 'any' because it does not have a type annotation
// and is referenced directly or indirectly in its own initializer.
currentNode = nextNode;
}
} |
BTW, using @JoostK's example, if you removes the asignation, error goes away... 😆 interface Node {
next: Node | null;
}
function test(node: Node) {
let currentNode: Node | null = node;
while (currentNode !== null) {
const nextNode = currentNode.next; // No error
// currentNode = nextNode; // Uncomment it, and error comes back
console.log(nextNode);
}
} |
Removing the assignment removes the circular nature of |
A new one in 4.7.0-beta #48708 |
The error also goes away if you simply move just the initialization out of the loop: function extentOne(nums: number[]) {
let result: [number, number] | null = null;
let oldMin, oldMax;
for (const num of nums) {
if (!result) {
result = [num, num];
} else {
[oldMin, oldMax] = result;
result = [Math.min(num, oldMin), Math.max(num, oldMax)];
}
}
return result;
} It also goes away if you remove function extentTwo(nums: number[]) {
if (nums.length === 0) {
return null
}
let result: [number, number] = [nums[0], nums[0]];
for (const num of nums) {
if (!result) {
result = [num, num];
} else {
const [oldMin, oldMax] = result;
result = [Math.min(num, oldMin), Math.max(num, oldMax)];
}
}
return result;
} |
I went to take a look at this old issue today, only to find that @babakks had recently fixed it in #56753. Nice! 🎉 The example in the original issue already works on the TS 5.4-beta playground and the fix should be out in the final 5.4 release in the next few weeks. |
Unfortunately there's still a limitation for #33191 (comment), which continues to report an error (it's a scenario without binding elements). Interestingly, #33191 is quite similar but that one has been resolved in 5.0, so perhaps my case falls under #42529 (comment). |
@JoostK maybe open up a new issue, then? I don't see why your code from #33191 (comment) should be flagged as circular. |
It is circular
|
What feels funny about this is that there's a declared type for |
I recommend reading #45213 for a long discussion of the practicality of "falling back" |
@danvk I'm glad that fix partially helped with this issue. |
This issue is effectively a design limitation as @RyanCavanaugh describes here. The "fix" in #56753 is more of an accident because the logic in that PR suppresses circularity errors in manner that isn't consistent. We're reverting that logic in #59183 and the design limitation continues to exist. |
TypeScript Version: 3.6.2
Search Terms:
Code
Expected behavior:
No error.
Actual behavior:
I'm really struggling to see where the circularity comes in. The type of
result
is shown as[number, number]
in that branch, so I'd assume destructuring it would result in twonumber
types.Removing the destructuring and using array accesses is equivalent but produces no error:
Playground Link: link
Related Issues:
The text was updated successfully, but these errors were encountered: