-
Notifications
You must be signed in to change notification settings - Fork 12.8k
typescript passes number | Promise<number>
as if it were number
(or something like that)
#52036
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
|
The difference is that const n: number | Promise<number> = Promise.resolve(0) as number | Promise<number>;
console.log(n >= 0); // typechecks, as with foo.n |
Thanks for explaining the difference @fatcerberus. Now why |
number | Promise<number>
as if it were number
(or something like that)
People run into this a lot; long story short is that this is considered the lesser of two evils as opposed to the alternative. See for example #50444 (comment):
Yeah, agree 100%. That really shouldn't typecheck. |
I've checked what happens under the hood and it seems that it's enough for left and right types to be comparable in either direction: This is quite surprising but apparently it's even OK to compare class instances (test case taken from the TS test suite): TS playground I spiked a potential improvement for the reported case here but I'm not totally sure if this is something that the TS team would like to incorporate. |
It seems weird that it’s using the comparability relation for that. That |
Yeah I guess EcmaScript allows pretty much anything to be on either side of a Relational Operator and the runtime semantics of that, when given mixed inputs gets unclear (to put it mildly). Not sure where TypeScript stands. Does it wants to stick with the clear subset (comparing two numbers or two strings) or does it want to extend to ES territory? |
Technically, there is no undefined behavior in ECMAScript; everything is well-defined by the specification, so TypeScript almost by definition must be pragmatic about what it considers an error (e.g. it is not allowed to call Applying relational operators to arbitrary objects definitely feels to me like something that is likely to be a coding mistake and should produce a TS error. The main question is whether that behavior can be changed now without causing disruptive breaking changes. |
I believe this was intentionally allowed at one point. Since object operands always return false in relational operators, I'd argue that it's at least somewhat coherent to do this. #41163 (comment) We'll look at what the PR runs turn up; maybe no one actually does this on purpose. |
I dug through the archives and found #10120 as the most canonical investigation of this, as well as #5156 It's a bit tricky since I think there's a reasonable argument that function fn(x: number | (() => string)) {
if (x > 10) {
}
} is every bit as valid of a type guard on But the fact that we're not currently narrowing function fn(x: number | string) {
if (x > 10) {
}
} is clearly every bit as suspect as This kind of has the same flavor to me as the problem of boolean coercion we see elsewhere. There's code like function fn(x: object | undefined) {
if (x) { }
} which seems very cromulent, and code like function fn(x: number) {
if (x) { }
} which also seems very cromulent, but code like function fn(x: number | undefined) {
if (x) { }
} seems like a giant red flag because it's not really clear if the author fully thought through the falsiness of The same rule seems like what you want here - you can do |
Bug Report
Something is very weird that makes typescript pass
Promise<number>
as if it were anumber
when it is an object field. Typescript correctly recognizes thatPromise<number>
is not a number when it is a plain variable. Weird.🔎 Search Terms
promise numeric
🕗 Version & Regression Information
I believe this has always existed in typescript. I have tried multiple versions on playground (from 3.3 up to 5). I did read the FAQs in https://github.com/Microsoft/TypeScript/wiki/FAQ#common-bugs-that-arent-bugs and found nothing related.
⏯ Playground Link
Playground link with relevant code
💻 Code
🙁 Actual behavior
The last expression passes the type checker even though it is clearly wrong.
🙂 Expected behavior
That the last expression is rejected with
Operator >= cannot be applied to Promise<number> and number.
.The text was updated successfully, but these errors were encountered: