-
Notifications
You must be signed in to change notification settings - Fork 12.8k
instanceof incorrectly guards else block #54684
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
It's a design limitation. Unless your classes have a private member they're treated structurally, and structurally both your classes are the same. |
The problem here though is the the |
Doing Again, it's a design limitation. It's best practice to never have fully public classes. |
Yes, this is exactly why it shouldn't remove the E.g. const bus: Car | null = new Bus(); // this is valid, Bus and Car have the same interface
if(bus instanceof Car) {
bus; // type: Car (since null would never pass this guard, it makes sense to remove it from the type)
} else {
bus; // type: Car | null (Another type that implements Car could not be an instanceof Car, so it
// should be typed as so. Currently this would just be typed null, which doesn't
// reflect the runtime behavior where it can be an instance of Bus in this case as well)
} This is already how this logic works for interface types, I see no reason as to why this can't be changed to follow that logic as well. |
This will cause issues on the opposite side of the spectrum. 🤷♂️ Generally it's assumed you either use structurally typed classes or |
Yeah I definitely get what you mean by it possibly being confusing for new learners -- I don't think that a feature being slightly confusing (but still making logical sense once you know that the type Car is an interface that doesn't only accept Car objects) should stop it from being implemented though when the alternative is to just have it not reflect what's actually happening at runtime. Worst-case scenario this could be put behind a compiler flag, but I definitely think it should be addressed. |
Duplicate #33481 |
In particular #33481 (comment)
|
Aside, this used to be the behavior and everyone hated it. |
This issue has been marked as "Duplicate" and has seen no recent activity. It has been automatically closed for house-keeping purposes. |
Bug Report
When using
instanceof
, theelse
block will remove the type of the class that was guarded from the type's union, even though the variable could have been assigned to a different object with the same interface.🔎 Search Terms
instanceof guard if else interface class never
🕗 Version & Regression Information
Noticed on TypeScript 5.1.3
Still occurs on Nightly
This is the behavior in every version I tried, and I reviewed the FAQ for entries about common bugs that aren't bugs
⏯ Playground Link
Playground example
💻 Code
🙁 Actual behavior
In this example, an instance of
Bus
is passed to a function that takes a value with the interface ofCar
. Then, aninstanceof
guard is done to check ifcar
is an instance of the classCar
. Because of this, the else block inferscar
asnever
, and errors when attempting to call thedrive()
method. Although,Bus
both follows the interface ofCar
and failsinstanceof Car
, leading to inconsistent behavior between the TS Compiler and JS, wherecar
actually has a value at runtime, and should not be inferred as anever
type.🙂 Expected behavior
Ideally, the fix for this should be that
instanceof
guards do not remove types inelse
blocks, so within itcar
should continue to be typed as aCar
.The text was updated successfully, but these errors were encountered: