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
SUGGESTION: Set and Map '.has' method as type guard #18781
This is a small suggestion, but I think it can be interesting to bring this type of characteristics to the spirit of the typescript language.
Code
functionactual(value: string|number){letnumbers=newSet<number>();if(numbers.has(value))// Error: Type 'string' is not assignable to type 'number'.value// we need to doif(numbers.has(valueasnumber))value=valueasnumber}declareclassMySet<T>{has(elem: any): elem is T;}functionsuggested(value: string|number)letnumbers=newMySet<number>();if(numbers.has(value))// OK, we are doing a legal checkingvalue// <= value is a 'number'}
I don't think this is a great idea, for a few reasons. The most obvious one is this:
declareletnumbers: Set<number>;declareletvalue: string|number;if(numbers.has(value)){value+2// narrowed to number, okay}else{value.charAt(0);// narrowed to string?!}
If a Set<T> doesn't contain a value, then the value isn't of type T?
Less obvious but possibly more important is that such a declaration subverts the point of type checking. Mistakes like this will no longer be caught:
letnums=[0,1,2];// array of numbersnumbers.has(nums);// oops, no error!
So I wouldn't want to see this added to the standard libraries.
If these objections don't sway you and you still find this change useful for your own work, you could always modify or augment your local declaration of Set:
// put this in your own code to reap its benefitsinterfaceSet<T>{has(elem: any): elem is T;}
Cheers!
Reacted by Aluan Haddad, Zheeeng, Leah Einhorn, owengc, Antoine ESTEVE, Dongook Lee, Gerardo Hidalgo-Cuellar, Casey Fulton, Jarek Rencz, Hyunbin Seo and 2 more
Is there a very compelling scenario for this? I get the idea, but like Joe Calzaretta (@jcalz) said, this means you could easily screw up and pass anything accidentally which lead to some frustrating behavior.
There's nothing super wrong with adding your own overload if you feel it'd help you out a lot.
Wouldn't the narrower use-case, where has is just used just as non-undefined typeguard, still be really useful? I often have situations along the lines of:
functionfoo(map: Map<String,String>,key: String): String{if(map.has(key)){returnmap.get(key);// Type 'String | undefined' is not assignable to type 'String'.}return"";}
It feels odd and incomplete that TypeScript doesn't know that map.get(key) in the if's clause must return not-undefined thanks to that has.
Reacted by Robert S., omid habibi, Tomasz Kasperczyk, Julian Dax, Olga, Travis Wagner, Rhys Lloyd, Luis Ramos, Serge Shirokov, Christopher Hsiao and 9 more
Edit: I actually tested it and it prevents wider type narrowing, but it also causes the narrow type to resolve to never in the else case.
declareletnumbers: Set<number>declareletvalue: boolean|numberdeclareletvalue2: numberif(numbers.has(value)){value+2// no narrowing}else{value.charAt(0)// no narrowing}if(numbers.has(value2)){value2+2// number as is.}else{value2.charAt(0)// narrowed to never}
Activity
jcalz commentedon Sep 27, 2017
I don't think this is a great idea, for a few reasons. The most obvious one is this:
If a
Set<T>doesn't contain a value, then the value isn't of typeT?Less obvious but possibly more important is that such a declaration subverts the point of type checking. Mistakes like this will no longer be caught:
So I wouldn't want to see this added to the standard libraries.
If these objections don't sway you and you still find this change useful for your own work, you could always modify or augment your local declaration of
Set:Cheers!
mhegazy commentedon Sep 28, 2017
Duplicate of #13086
jcalz commentedon Sep 28, 2017
It's not a duplicate; #13086 is about performing a
get()after ahas(). This is... something else.DanielRosenwasser commentedon Sep 28, 2017
Is there a very compelling scenario for this? I get the idea, but like Joe Calzaretta (@jcalz) said, this means you could easily screw up and pass anything accidentally which lead to some frustrating behavior.
There's nothing super wrong with adding your own overload if you feel it'd help you out a lot.
fasiha commentedon Aug 9, 2018
Wouldn't the narrower use-case, where
hasis just used just as non-undefinedtypeguard, still be really useful? I often have situations along the lines of:It feels odd and incomplete that TypeScript doesn't know that
map.get(key)in theif's clause must return not-undefined thanks to thathas.jcalz commentedon Aug 9, 2018
Ahmed Fasih (@fasiha) you are looking for #13086
RyanCavanaugh commentedon Aug 13, 2018
Agree with Joe Calzaretta (@jcalz) this doesn't seem like a good solution (to say nothing of the problem)
avin-kavish commentedon Aug 24, 2022
Wouldn't this prevent the
elsecase problem that Joe Calzaretta (@jcalz) is describing?Edit: I actually tested it and it prevents wider type narrowing, but it also causes the narrow type to resolve to never in the else case.