You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Narrowing types by typeof inside switch (true) does not work #37178
letx: string|undefined;if(typeofx!=='undefined'){x.trim();// works as expected}switch(true){casetypeofx!=='undefined':
x.trim();// thinks x is potentially undefined}
Which makes this a duplicate of... well, I couldn't find an existing ticket. But I'm reasonably sure narrowing === true and === false patterns was rejected before because it adds perf costs for an uncommonly used idiom.
Reacted by Yaksh Bariya, Scott Morse, jiaSheng, Felix, Arturo Mendivil, Nikolay Lanets, Ilia Ilintsev, Hector Ayala, Mahmudur Rahman, Jaiden Fairoze and 5 more
Not arguing at all that the shape is a bit odd, but if there are many variants for what you're switching over then it is more readable than a bunch of if/else if.
Reacted by Keir Lavelle, Ondřej Huta, Tomáš Polomský, Kyle Shevlin, Arturo Mendivil, darcyrush and Adam Obuchowicz
changed the title [-]Narrowing types inside switch statement does not work[/-][+]Narrowing types by `typeof` inside `switch (true)` does not work[/+]on Mar 3, 2020
Switching over the type is not equivalent in case you have multiple possible matches that are staggered based on the value, e.g.:
switch(true){casetypeofprocess.env.X!=='undefined':
// we favor env var X over Y if it is definedbreak;casetypeofprocess.env.Y!=='undefined':
// we fall back to Y if X is not definedbreak;}
This is not possible by switching over the type only, it really needs the actual value.
Shall I close this issue as something that will never be fixed/implemented due to performance issues for an outlier case?
switch(true){casetypeofprocess.env.X!=='undefined':
// we favor env var X over Y if it is definedbreak;casetypeofprocess.env.Y!=='undefined':
// we fall back to Y if X is not definedbreak;}
over
if(typeofprocess.env.X!=='undefined'){// we favor env var X over Y if it is defined}elseif(typeofprocess.env.Y!=='undefined'){// we fall back to Y if X is not defined}
Two come to mind:
• readability for big amounts of cases
• being able to use fall-throughs for overlapping cases
Having said that I understand it is an edge case. I came across this pattern in a bigger codebase and wanted to make a change. That's when I noticed that the types are not narrowed in each case.
Reacted by ExE Boss, Jay Faulkner, Anatoliy Arkhipov, Joram van den Boezem, Eric Crosson, Slick Kilmister, Pokai Chang, Keir Lavelle, Guilherme Tod, Ondřej Huta and 26 more
Has there been any opdate or in progress work on this?
Fourth adwantage is when having to narrow an input which can be a primitive or a specific object type/class instance:
functionprocessInput(input: string|RegExp|SomeType){switch(true){casetypeofinput==='string':
// <code for string....>breakcaseinputinstanceofRegExp:
// <code for regex....>breakcaseisSomeType(input):
// <code for SomeType....>break}// <some more code....>}
Reacted by Noah Lange, Anna Bocharova, Mark Macdonald, nithishjv, Kyle Shevlin, ElPrudi, Meirion Hughes and dystopiandev
Marc Harter (@wavded) use !! (doublebang) instead. You'll still have the issue of this thread but TS2532: Object is possibly 'undefined'. should be gone
The doublebang is just 2 consecutive NOT operations, the first converts the value to truthy/falsy and inverts it, the second undoes the inversion. eg:
Marc Harter (@wavded) Oh, my apologies, with the link ExE Boss (@ExE-Boss) shared i was just thinking about type inference of the Boolean() constructor, and didn't realise that the error would be the same.
So yes, you are having the same problem as mentioned in this issue.
The easiest fix got you would probably be to tell typescript that these values are non-nullable. eg. with the Non-null assertion operator.
letgeocode=useSelector((s: T.State)=>s.geocode)!// <- note the added `!`letzips=useSelector((s: T.State)=>s.zips)!letcrs=useSelector((s: T.State)=>s.crs)!
I try not to pollute open issues with fluff like "me too!", but in the related closed thread I was surprised to see this commented as a 'wontfix' as it is not a 'common pattern'. Those comments were in 2016. I find this pattern a very clean and elegant approach that can be reused across an entire codebase to consistently handle very different scenarios.
Anecdotally, I see this pattern more and more in the wild.
Reacted by Noah Lange, Sergey Ukustov, Ilµs, Nicolas, Jakub Meinlschmidt, Henri Cazottes, kWozniak-tt, Gagik Muradyan, __JM__, Sergey Khokhlachev and 6 more
Anecdotally, I see this pattern more and more in the wild.
Best argument I've heard for switch(true) is that sometimes you need to execute only one of lots of possible things and it most succinctly conveys that. While you can just else if a bunch of times, you have to read all the way through to make sure there's no missing else etc.
It's not often I need it but when I do then edge cases like this are a real shame.
Reacted by Sebastian Leukhin - mallchel, Quim T., dystopiandev, Alexey Shamrin and Richard Wise
when (x) {
1->print("x == 1")
2->print("x == 2")
else-> {
print("x is neither 1 nor 2")
}
}
enumclassColor {
RED, GREEN, BLUE
}
when (getColor()) {
Color.RED->println("red")
Color.GREEN->println("green")
Color.BLUE->println("blue")
// 'else' is not required because all cases are covered
}
when (getColor()) {
Color.RED->println("red") // no branches for GREEN and BLUEelse->println("not red") // 'else' is required
}
when {
x.isOdd() ->print("x is odd")
y.isEven() ->print("y is even")
else->print("x+y is odd")
}
Hoping TS can at least supports what OP mentioned.
Activity
nmain commentedon Mar 3, 2020
Never seen code like that before 😄. If you rewrite the
ifstatement to be roughly equivalent to theswitchstatement, you get the same failure:Which makes this a duplicate of... well, I couldn't find an existing ticket. But I'm reasonably sure narrowing
=== trueand=== falsepatterns was rejected before because it adds perf costs for an uncommonly used idiom.joscha commentedon Mar 3, 2020
Not arguing at all that the shape is a bit odd, but if there are many variants for what you're switching over then it is more readable than a bunch of if/else if.
[-]Narrowing types inside switch statement does not work[/-][+]Narrowing types by `typeof` inside `switch (true)` does not work[/+]DanielRosenwasser commentedon Mar 3, 2020
The crux of this was filed at #8934 discussed a bit at #2214, but I think the overall guidance is to write something along the lines of
In your case it would be the following:
joscha commentedon Mar 4, 2020
Thanks Daniel Rosenwasser (@DanielRosenwasser) - maybe I shouldn't have simplified the example so much :)
Switching over the type is not equivalent in case you have multiple possible matches that are staggered based on the value, e.g.:
This is not possible by switching over the type only, it really needs the actual value.
Shall I close this issue as something that will never be fixed/implemented due to performance issues for an outlier case?
RyanCavanaugh commentedon Mar 4, 2020
What's the advantage of
over
?
joscha commentedon Mar 4, 2020
Two come to mind:
• readability for big amounts of cases
• being able to use fall-throughs for overlapping cases
Having said that I understand it is an edge case. I came across this pattern in a bigger codebase and wanted to make a change. That's when I noticed that the types are not narrowed in each case.
anatoliyarkhipov commentedon Jun 10, 2020
The third advantage is that in some cases it tastes as poor man's pattern matching.
KilianKilmister commentedon Sep 13, 2020
Has there been any opdate or in progress work on this?
Fourth adwantage is when having to narrow an input which can be a primitive or a specific object type/class instance:
wavded commentedon Sep 21, 2020
I also ran into this. Typescript says
geocodeandzipsare possibly undefined even though the case statement rules that out as a possibility.ExE-Boss commentedon Sep 21, 2020
Marc Harter (@wavded) Your case won’t be fixed by this because of #16655.
KilianKilmister commentedon Sep 22, 2020
Marc Harter (@wavded) use
!!(doublebang) instead. You'll still have the issue of this threadbutTS2532: Object is possibly 'undefined'.should be goneThe doublebang is just 2 consecutive
NOToperations, the first converts the value totruthy/falsyand inverts it, the second undoes the inversion. eg:So your switch would look something like this:
wavded commentedon Sep 22, 2020
Slick Kilmister (@KilianKilmister) I get the same error unfortunately.
KilianKilmister commentedon Sep 22, 2020
Marc Harter (@wavded) Oh, my apologies, with the link ExE Boss (@ExE-Boss) shared i was just thinking about type inference of the
Boolean()constructor, and didn't realise that the error would be the same.So yes, you are having the same problem as mentioned in this issue.
The easiest fix got you would probably be to tell typescript that these values are non-nullable. eg. with the Non-null assertion operator.
Check out the docs, they explain it.
I'd still suggest generally using the
!!instead ofBoolean()though. It's considered the more favourable practicepolomsky commentedon Apr 15, 2021
I have similar usecase:
And I am using this syntax in javascript because it looks better than chain of if else. Sadly can not use in typescript
ScreamZ commentedon Jan 26, 2022
Exact same issue, maybe someone has some workaround for this ? Anders Hejlsberg (@ahejlsberg) Sheetal Nandi (@sheetalkamat) Nathan Shively-Sanders (@sandersn)
darcyrush commentedon Aug 31, 2022
I try not to pollute open issues with fluff like "me too!", but in the related closed thread I was surprised to see this commented as a 'wontfix' as it is not a 'common pattern'. Those comments were in 2016. I find this pattern a very clean and elegant approach that can be reused across an entire codebase to consistently handle very different scenarios.
Anecdotally, I see this pattern more and more in the wild.
Nathan Shively-Sanders (@sandersn) Ryan Cavanaugh (@RyanCavanaugh) Would you still consider this an uncommon pattern today?
jukibom commentedon Dec 29, 2022
Best argument I've heard for switch(true) is that sometimes you need to execute only one of lots of possible things and it most succinctly conveys that. While you can just
else ifa bunch of times, you have to read all the way through to make sure there's no missingelseetc.It's not often I need it but when I do then edge cases like this are a real shame.
Thijs-van-Drongelen commentedon May 8, 2023
We have a connection broker with lots of different protocols, so our connection class has alot of different configuration types.
When a new connection is submitted by a user, the backend needs to know what connection handler needs to configure the connection. Here is an example:
Please tell me if there is a better way, But rn I'm thinking I'd like this feature
epicmet commentedon Aug 19, 2023
Any updates on this issue?
zeroarst commentedon Sep 13, 2023
In Kotlin,
whenexpression is much better in terms of intuition and usability.https://kotlinlang.org/docs/control-flow.html#when-expression
Hoping TS can at least supports what OP mentioned.