Skip to content

TypeScript can't infer correct type from while loop if while condition is given a promise #55300

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

Open
BlackAsLight opened this issue Aug 8, 2023 · 5 comments
Labels
Help Wanted You can do this Possible Improvement The current behavior isn't wrong, but it's possible to see that it might be better in some cases
Milestone

Comments

@BlackAsLight
Copy link

πŸ”Ž Search Terms

promise in while loop condition

πŸ•— Version & Regression Information

  • This is the behavior in every version I tried, and I reviewed the FAQ for entries about Bugs that aren't bugs

⏯ Playground Link

https://www.typescriptlang.org/play?ts=5.2.0-dev.20230807#code/GYVwdgxgLglg9mABAZwDYFN0AcAUBbZALkTBDwCN0AnASmIAUq48Zl0AeKKkdAPkQDeAKESIq6KCCpIw6AO6JGzVhy49eOAIaIAvPzZQAKjDzo4IKDhw1d-TTjXoaAGkQEaNIQF8hQzcgBPSERQSFgERHQAD008LAwARmsGJhY2dmQuGDAAc35hAEgMKEQAN01UHmJMqmycxAAfRHAAE3RgbPQWoQK5AAsYDEQHbidBHoLNOU0YErRMXABWAAZVzwKC8sr0XUQAckW9ifJxTQBrHp8C8UlpMoqeb19-IIgQ8Gh4JGjY+PQAJmSilSKgyWVy+R6xXu22q4PqTVa7U63V6AyGWmmsxQGGwOBWaxshU2Dx2On2h2OpwuBSuNykSC2jy8QA

πŸ’» Code

function sleep(ms: number): Promise<true> {
  return new Promise<true>(a => setTimeout(() => a(true), ms))
}

async function example1(): Promise<string> {
	let value: string | undefined
	while (true) {
		await sleep(5000)
		value = '5'
		break
	}
	return value
}

async function example2(): Promise<string> {
	let value: string | undefined
	while (await sleep(5000)) {
		value = '5'
		break
	}
	return value
}

πŸ™ Actual behavior

In example2, TypeScript can't infer the type of value and that it should be now a string and not undefined simply because the Promise that returns true in the while loop has been moved to the while condition instead of the body of the while loop.

πŸ™‚ Expected behavior

The expected behaviour should be that TypeScript should be able to infer that it is still a string at the return statement just like in example1

@jcalz
Copy link
Contributor

jcalz commented Aug 8, 2023

Duplicate of #30551 possibly?

#29323 then

@fatcerberus
Copy link

await is a red herring here - if (true) vs. if (trueTypedValue) are treated differently by CFA, iirc

@fatcerberus
Copy link

fatcerberus commented Aug 8, 2023

Explanation: #29323 (comment)

Basically, it's a design limitation and unlikely to be fixed easily. CF nodes are created conservatively, before types are known. Things like if (true) and if (false) work only because those are special-cased syntactically.

I do question why you would write this code - if you know the condition is always going be true, why make it conditional in the first place?

@RyanCavanaugh RyanCavanaugh added the Possible Improvement The current behavior isn't wrong, but it's possible to see that it might be better in some cases label Aug 8, 2023
@RyanCavanaugh RyanCavanaugh added this to the Backlog milestone Aug 8, 2023
@RyanCavanaugh RyanCavanaugh added the Help Wanted You can do this label Aug 8, 2023
@RyanCavanaugh
Copy link
Member

I'm not 100% sure I buy my previous explanation as applies to this case. The CFA nodes are there and we can resolve the type without circularity in this case when assessing reachability.

That said, it's obviously not a super useful fix in terms of addressing "real" code.

@BlackAsLight
Copy link
Author

BlackAsLight commented Aug 10, 2023

I do question why you would write this code - if you know the condition is always going be true, why make it conditional in the first place?

I like to put the sleep command in the while condition to simply write less code. I always make my sleep command return true in the event I'd want to use it in some condition.

If for example though I wanted a do-while loop and the body of that loop had several conditions with some calling continue, I wouldn't want to put the sleep function just above all those continue keywords.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Help Wanted You can do this Possible Improvement The current behavior isn't wrong, but it's possible to see that it might be better in some cases
Projects
None yet
Development

No branches or pull requests

4 participants