-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Variable modified in loop supposedly "referenced directly or indirectly in its own initializer" #43047
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
|
It is? How so? Also note that adding a type annotation to currentValue on line 9 fixes the problem: let foo: {value:number} | undefined;
function bar() {
foo = {value: 1};
while (true) {
const currentFoo = foo; // no error
if (currentFoo) {
const currentValue: number = currentFoo.value; // type annotation added here -- no error
foo = {value: currentValue+1};
if (currentValue > 1) break;
}
}
} |
Because the kinds of values that can inhabit |
Would it be reasonable to automatically fall back to the type that Even sticking to the very first type I know my terminology above isn't very precise, but my mental type-checking thought process goes:
Basically, I think that this case can be solved by applying less advanced type inference than what the compiler is currently trying to do... |
Silently falling back to the declared type is going to just make things more confusing in the cases where a circularity exists, because then it will often look like narrowing is broken in much more subtle ways. |
I can see that being confusing, but only in the case that the result has a type error. Is it possible to try the fallback and only use it if it works? |
"Do this thing if it happens to make the program pass, otherwise do this other thing" logic is |
I guess the best I can hope for then is a clearer error message :) |
#43708 is considered a dup of this bug, and I don't want to beat a dead horse (I do have a workaround) but in principle it seems like ts ought to be able to figure that case out (this is the minimal repro from that bug report): declare function foo(x: string | undefined): Promise<string>
async () => {
let bar: string | undefined = undefined;
do {
const baz = await foo(bar); // ERROR HERE
bar = baz
} while (bar)
} In this case, the return type of foo is always |
Your example seems a little different, because it involves async/await: if I change |
Facing the same issue. Same as with #43708, it works when removing the The temporary workaround we're using: explicitly casting the "circular" value. Example (with the declare function myQuery(input: { lastId: number | undefined }): Promise<{ entities: number[] }>;
async function myFunc(): Promise<void> {
let lastId: number | undefined = undefined;
while (true) {
const { entities } = await myQuery({
lastId,
});
lastId = entities[entities.length - 1];
}
} Workaround (no error): declare function myQuery(input: { lastId: number | undefined }): Promise<{ entities: number[] }>;
async function myFunc(): Promise<void> {
let lastId: number | undefined = undefined;
while (true) {
const { entities } = await myQuery({
lastId,
});
lastId = entities[entities.length - 1] as number | undefined;
}
} |
Not sure if this is helpful, but here's a minimal repro (without async-await syntax)
|
Here is another very simple repro: function test()
{
let test1: number | undefined = 42;
if (test1 === undefined)
{
return;
}
for (let i = 0; i < 10; i++)
{
// test1: Object is possibly 'undefined'. ts(2532)
// 'test2' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer.ts(7022)
const test2 = test1 + 1;
// If I remove this line everything is fine
test1 = test2;
}
} |
All of these examples are circularities 🙃 To recap: TypeScript can avoid erroring in some (but not all) cases of circularities. This does mean that it's possible to write two programs which are slightly different, one of which will have a circularity error, one of which will not. The cases that we can't avoid issuing a circularity error on are, generally speaking, impossible to fix without rearchitecting the entire type checker. The existence of cases where we successfully avoid issuing a circularity error in the presence of a possible circularity doesn't change any of this. In general we won't make things broadly worse for the sake of consistency so suggestions to "error always" will not be accepted. |
Bug Report
The following code produces this error on two lines:
This is a reduced repro case from a real code snippet. It seems like maybe the error is arising when the compiler tries to refine the types of these variables by looking at assignment expressions. But the result is unintuitive and unhelpful.
Expected behavior:
At worst, the compiler should just give
currentFoo
the same type as the declaration offoo
, and this would be better than the current behavior.TS playground
🔎 Search Terms
implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer
Possibly related issues: #16892, #22390, #35546
🕗 Version & Regression Information
The text was updated successfully, but these errors were encountered: