Skip to content

Refinement in async function #61365

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

Closed
philipnilsson opened this issue Mar 6, 2025 · 3 comments
Closed

Refinement in async function #61365

philipnilsson opened this issue Mar 6, 2025 · 3 comments

Comments

@philipnilsson
Copy link

philipnilsson commented Mar 6, 2025

πŸ”Ž Search Terms

"refinement async function"

πŸ•— Version & Regression Information

  • This is the behavior in every version I tried, and I reviewed the FAQ. No entries matching "refinement" and nothing matching "async" or "await"

⏯ Playground Link

https://www.typescriptlang.org/play/?target=99&ts=3.8.3#code/IYZwngdgxgBAZgV2gFwJYHsIwEbAE4AUAlDAN4CwAUDDTHgKbIJ5YT0DuMACnugLaoQ9AgGsYAXgB8MIcgAqqPvXQJkogDQwAjAAYdRIgG4qAXypVQkWIhQYscdOmJkqtGABtGMZPRDIAXDAQCO7uMAA+ZDAAFvSh6IEA5OzoeO4AJokwJhJBIe7G1LRQmCDongB07ugA5gSJ0agAhIlE5kU0sgpKKmrOUi4dbt6+yLmkMXHVSSlpmWZDJm2UrrTA7MCoY7iERqs0JRBlldV1iT5+APyJmhfIy8MA9I90SBCoEDXesTAADrw1PDAPgyaLodggb7AMZ3GCCGAAAwmsXiM1SGSyJgROFUMDkYF+9AAylA8KhfmMPiU8AwoMh3GAYPsaM86PQ4B9fHCYeg8qFNEJ6AJPgy4TUIKkPl9kNFod96AxEpDgFh1psxuxGlBojA+MBGcB4pwZfQYKAQKhxUoIDyYsBfoT7Kg8H5mXdLhUUdVCgsqA4nHsVpQgA

πŸ’» Code

async function bar() {
    return new Promise(k => setTimeout(k, 100));
}

async function foo() {
    let test: null | { hello: 'world' } = null;
    console.log('hi!')

    setTimeout(() => {
        test = { hello: 'world'}
    })

    await bar();
    console.log('test?', test)
     // running the program shows that test is `{ hello: 'world' }` but TypeScript incorrectly 
     // refines it to null, seemingly ignoring that there's an await which may allow the assignment to happen first
    test?.hello;
}

foo();

πŸ™ Actual behavior

Getting a type error, where TypeScript refined the type of test to null

πŸ™‚ Expected behavior

The inferred type of test should be null | { hello: 'world' }

Additional information about the issue

There seems to be an issue where TypeScript ignores awaits (and yield/yield*) when doing refinement. It seems to me that at any point after an await you can no longer assume a refinement holds true.

I understand perhaps this may be a necessary tradeoff to avoid false negatives in many cases. However since there is an explicit assignment to a let declared variable in the same function it seems a bit funny. If this is a known limitation perhaps an entry in the FAQ could be added.

@MartinJohns
Copy link
Contributor

MartinJohns commented Mar 6, 2025

Duplicate of #9998. There's even a dedicated issue template for this exact issue: https://github.com/microsoft/TypeScript/blob/main/.github/ISSUE_TEMPLATE/types-not-correct-in-with-callback.md?plain=1

@philipnilsson
Copy link
Author

philipnilsson commented Mar 6, 2025

@MartinJohns It's not obvious to me that the same is true for an await based on the above template.

An await could be though of as desugaring into promise.then(callback), where callback is the rest of the computation, where if applying your rule of "narrowings are not respected in callbacks" you'd expect the narrowing to no longer be present, exactly the opposite of what you claim, no?

Anyway, I wasn't able to find the precedent here so if this still counts as a duplicate I can close and it's up to you if you think it warrants adding to the FAQ / template.

@philipnilsson
Copy link
Author

Since there seems to be discussion here #9998 (comment) I'll just close though.

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