Skip to content

Unexpected circularity error when variable is initialized from a class member #61606

New issue

Have a question about this project? No Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “No 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? No Sign in to your account

Open
Gr3q opened this issue Apr 22, 2025 · 3 comments · May be fixed by #61608
Open

Unexpected circularity error when variable is initialized from a class member #61606

Gr3q opened this issue Apr 22, 2025 · 3 comments · May be fixed by #61608
Labels
Bug A bug in TypeScript Help Wanted You can do this
Milestone

Comments

@Gr3q
Copy link

Gr3q commented Apr 22, 2025

🔎 Search Terms

loss of type, for loop, for-loop, class field

🕗 Version & Regression Information

  • This changed between versions ______ and _______
  • This changed in commit or PR _______
  • This is the behavior in every version I tried, and I reviewed the FAQ for entries about _________
  • I was unable to test this on prior versions because _______

⏯ Playground Link

https://www.typescriptlang.org/play/?#code/JYOwLgpgTgZghgYwgAgIIAd0BtgLmYAexGQG8AoZK5YAEwC5kBnMKUAcwG5zLq9J2hKAE9GFahJoNmrDtwkBfckvIIscJkzSYc-IiC3jq6AK4AjXcgBioWhmy58+gBQBHE9FEy2IdgEpGe10nYmQAH2QQEywsMl5JZCgIMBMoEiiY+WolFTUNLQAVCBY4iQBlCCwIBEg7HUcCYiZGCrAAHhYfdgA+ZABeSIgAd2RW5z8sqiCG-WbtBz0m8Mjo2IGMrEnkdmTRyura6cWDACFhAGF8CEERccYABTgoAjgsNoAlaqFaDtlfABo9u1OhxumDlhtSglkAB6GHIADqQgA1k9CCYQLRkABGRgAW0IADcUGAABbALQWQgIZE0Ax0FAwITILCEQjoeKSOGIlFojFYgBMLTgxOQAAMyRSAHRHEIGMXIMCEZBwZAIJpgRWkiAkExMEmk-CciTAGDIZySpgy+rHLR9e0rGJ+KHQ6hJFJpR2bY3ZHiu9UGTVJJjRMAPJ4vN6fdVQH4ggFA35dMG9AakBTcH1UJlQc0BkpwG1ygCSABFkIQzZapRUqjUIHUFnKmM6jK6qPnNYWm40SANq7Le1abJjBy5u8Fe2WJlnJKbzROZqF7etVq3Z-7iAQohAtq6VO2+Bq1VcbsIy-0VUXe1L+NchMIpXQ99DO1ee7NL8HQwBtO9nssAF1kAAfhAwYRlaJNQXGF8EkXW0pTgWhaGcBC5SfWgZ0PKhuXOQg8TxHUwBhDF1UI4itUZQgYkIIYOBZUASWVfUUGATUzCSOBkVIkBOIgbiNzdYpf3-B8gMvdChzg5AD2hd1UhIb8sDALYciAA

💻 Code

interface Application {
    id: string;

    category: {
        id: string;
    }
}

class Applications {
    public FindApplication(query: string): Application | null {
        return null;
    }
}

class Test {
    SelectedApplications: Set<string> = new Set();
    Applications: Applications | null = null;
    get SelectedApplicationsByCategory(): Partial<Record<string, Set<string>>> | null {
        // Workaround 1: move this block inside for loop
        // Workaround 2: Save this.Applications to a const then use that
        if (this.Applications === null) {
            return null;
        }

        const result: Partial<Record<string, Set<string>>> = {};

        for (const applicationID of this.SelectedApplications) {
            const application = this.Applications.FindApplication(applicationID);
            if (application === null) {
                continue;
            }

            const categoryID = application.category.id;
            const applications = result[categoryID] ?? new Set<string>();
            applications.add(application.id);
            // Comment/uncomment the following line to see it break/unbreak
            result[categoryID] = applications;
        }

        return result;
    }
}

🙁 Actual behavior

application has type: any. FindApplication returns Application | null, but that gets lost somewhere.

🙂 Expected behavior

type for application should be Application | null.

Additional information about the issue

See comments in code for workarounds and to see another line break type inference.

@Gr3q Gr3q changed the title Loss of type for class field in for loop Loss of type in for-of loop Apr 22, 2025
@RyanCavanaugh
Copy link
Member

Smallest repro I could find. Very weird.

interface Application {
    id: number;
}

const result: boolean[] = [];

class Test {
    appArray: Application[] | null = null;

    foo(): void {
        if (this.appArray === null) {
            return;
        }

        for (const idx of [0, 1]) {
            const app = this.appArray[idx];
            const categoryID = app.id;
            result[categoryID] = true;
        }
    }
}

@RyanCavanaugh RyanCavanaugh changed the title Loss of type in for-of loop Unexpected circularity error when variable is initialized from a class member Apr 22, 2025
@RyanCavanaugh
Copy link
Member

Bisects to #45974

@RyanCavanaugh
Copy link
Member

Shorter, looking at the PR

const result: boolean[] = [];
class Test {
    appArray: number[] | null = null;
    foo(): void {
        if (this.appArray === null) {
            return;
        }
        for (let i = 0; i < 1; i++) {
            const app = this.appArray[0];
            const appRef = app;
            result[appRef] = true;
        }
    }
}

@RyanCavanaugh RyanCavanaugh added Bug A bug in TypeScript Help Wanted You can do this labels Apr 22, 2025
@RyanCavanaugh RyanCavanaugh added this to the Backlog milestone Apr 22, 2025
RyanCavanaugh added a commit to RyanCavanaugh/TypeScript that referenced this issue Apr 22, 2025
…erty key equivalence

Fixes microsoft#61606. Need PR results to see if this is worth it or not.
No Sign up for free to join this conversation on GitHub. Already have an account? No Sign in to comment
Labels
Bug A bug in TypeScript Help Wanted You can do this
Projects
None yet
2 participants