Skip to content
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

Inappropriate Type Narrowing on Iterative Variable Reassignment #56216

Closed
pedrodurek opened this issue Oct 24, 2023 · 2 comments
Closed

Inappropriate Type Narrowing on Iterative Variable Reassignment #56216

pedrodurek opened this issue Oct 24, 2023 · 2 comments

Comments

@pedrodurek
Copy link

pedrodurek commented Oct 24, 2023

πŸ”Ž Search Terms

"type narrowing", "type narrowing within loop"

πŸ•— Version & Regression Information

  • This is the behavior in every version I tried, and I reviewed the FAQ for entries about type narrowing.

⏯ Playground Link

https://www.typescriptlang.org/play?ts=5.2.2#code/FAFwngDgpgBAyiKEYF4YG9g2zAzoiAOQEMBbKALjxACcBLAOwHMscGoAPEBJKn5AD4wGAVwA2YgNzAAvsGABjAPYN81JABk6atAG0A5MX0AaGPoBGJswv0BdaWKggYACyjEAJvz4EYQ0RKowuJSwI7OEDRQAG7e8L7+IUEBocD4mtogAHQAZko0AKLECi4AFKXpRGRQAJSoAHwYrNjKqs7sAO5x-EGYOP3qVeTGzQPsXHEpo3KjdDkwpW6ePSirwRJ1fQPYS16+aJ380v0z-XMLkTH8m6P9l7EEWePc+8JQXQTHOKc49ytvHyQ0hkNXk4GgMEYOSgNCiHgAKpBYGhwVAlPNdvxgAB6bHYAB6AH5gEA

πŸ’» Code

type Step = {
    stepName: string
    nextStep: Step | null;
}

const stepList = ['a', 'b', 'c'];
let headStep: Step | null = null;
let prevStep: Step | null = null;

stepList.forEach((stepName) => {
    const newStep: Step = {
        stepName,
        nextStep: null
    }

    if (headStep === null) {
        headStep = newStep;
    }

    if (prevStep) {
        prevStep.nextStep = newStep;
    }

    prevStep = newStep;
})

type inferredType = typeof headStep
//  ^?

πŸ™ Actual behavior

type inferredType = typeof headStep
//  ^? type inferredType = null

πŸ™‚ Expected behavior

type inferredType = typeof headStep
//  ^? type inferredType = Step | null

Additional information about the issue

Whenever headStep is reassigned within the forEach loop, the Step gets filtered out from the original type (wrongly narrowing).

@RyanCavanaugh
Copy link
Member

Effects of callbacks aren't modeled in CFA, so your example is equivalent to

type Step = {
    stepName: string
    nextStep: Step | null;
}

const stepList = ['a', 'b', 'c'];
let headStep: Step | null = null;
let prevStep: Step | null = null;

type inferredType = typeof headStep
//  ^?

which is correct.

See #11498

@pedrodurek
Copy link
Author

Ohhh got it, thanks for the explanation @RyanCavanaugh! Just realised that I πŸ‘ the original issue at some point in the past. I'll close this one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants