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
Using string enum as key in {[key]: Type} throws not an index signature #22892
Expected behavior:
Both map calls succeed, because a string enum is essentially a {[key: string]: string}. I ought to be able to use it anywhere that needs something indexed by string (as long as the values are appropriate).
Actual behavior:
index.ts(14,5): error TS2345: Argument of type 'typeof Fruits' is not assignable to parameter of type 'StringDict'.
Index signature is missing in type 'typeof Fruits'.
index.ts(19,5): error TS2352: Type 'typeof Fruits' cannot be converted to type 'StringDict'.
Index signature is missing in type 'typeof Fruits'.
StringDict has a stronger contract than Fruits, since Fruits["someRandomString"] is not string; and thus Fruit is not a StringDict.
the oposite is true as well, since the type of Fruite.Mango is a specific literal type "MANGO" that is not just any string.
For these two issues the type assertion Fruits as StringDict fails.
consider defining the function as object or as generic function in K where K is the keys of the object passed, both would allow you to call it on Fruite. e.g.:
I feel like I ought to be able to pass a string enum into a function that requires a [string]: string and it should work. I understand your point about type theory, but it fails practically here.
Is the solution when I don't control map to do map(myEnum as {} as {[key: string]: string}? Not only is that ugly, but it doesn't protect me in the case that someone changes the shape of the enum (e.g. adding a non-string value).
it is unsafe, since the index signature on the enum is really string | undefined. but i suppose we can bend the rules here the same way we do for object literals... worth discussing.
The index signature on {a: 1, b: 2} is also really string|undefined, so accepting a string enum's potential for an undefined key feels consistent with that.
enumMyEnum{ValA=0,ValB=1,}typeIEnumTpProp<R>={[keyinkeyoftypeofMyEnum]: R};varX: IEnumTpProp<string>={ValA: "text1",ValB: "text2",0: "error"// expected: error; current: error; //OK};X[MyEnum.ValA]="no error??";// current: no error; expected: error // KOX[MyEnum[MyEnum.ValA]]="no error";// current: no error; expected: no error // OK
Reacted by avocadowastaken, houfeng, welljsjs, Vlad Dumbrava, Alex Petrik, Jon Bullock, Shadowless, Victor, Will, Tushin Nikolay and 89 more
Reacted by Nick, Kaelan Cooter, YoniH and Michael Bruce Allen
Reacted by Lucas Marques, Adam Hanna, Jakub Młokosiewicz, Kevin Donahue, Nick, S Kuijers, YoniH, Vlad, Michael Bruce Allen, David Pascoal and 2 more
Reacted by Nick, RF IT, YoniH and maxmarinich
Reacted by welljsjs, Tushin Nikolay, Yuriy Gyerts, A K Tolentino, Andy, Victor Bezerra, Aarif Khamdi, Alex Bjørlig, Mykola Riabchenko, Roman Khitin and 17 more
Reacted by Lucas Marques, Adam Hanna, Vitali Dziachuk, Samuel Gaona, Nick, Denys Ostapenko, S Kuijers, YoniH, Michael Bruce Allen, David Pascoal and 3 more
Reacted by Nick, Zufeng, YoniH, Michael Bruce Allen and Vladyslav
Gabriele (@dardino) i am afraid this is a different issue. all objects can be indexed with strings/numbers and result in an any if not defined. it should be reported as an error under --noImplicitAny.
Reacted by Brenton Simpson, Gabriele and Jan-Niklas
This would be super problematic because we always allow expressions of the form expr.propname if expr has a string index signature, so there would be effectively zero "typo protection" on propname. We don't want to be in the situation where removing or renaming a string enum key doesn't cause new errors to appear, or where misspelling a string enum key doesn't cause an error.
enumX{A='a',B='b',}typeValueOfX= `${X}`
typeY={[PinValueOfX]?: number;}letcc: Y={a: 0,c: 1,// error: c does not exist in type Y}
Reacted by Spencer Miskoviak, Gil Meir, Vladimir Kuznetsov, Filip Drgoň, undfndusr, Francesco Agnoletto, Kalugin Sergei, Dawson Booth, karts-with-freaking-lasers, Philip Aarseth and 2 more
Activity
mhegazy commentedon Mar 26, 2018
StringDicthas a stronger contract thanFruits, sinceFruits["someRandomString"]is notstring; and thusFruitis not aStringDict.the oposite is true as well, since the type of
Fruite.Mangois a specific literal type"MANGO"that is not just anystring.For these two issues the type assertion
Fruits as StringDictfails.consider defining the function as
objector as generic function inKwhereKis the keys of the object passed, both would allow you to call it onFruite. e.g.:or
appsforartists commentedon Mar 26, 2018
That's presuming I control the definition of
map.I feel like I ought to be able to pass a string enum into a function that requires a
[string]: stringand it should work. I understand your point about type theory, but it fails practically here.Is the solution when I don't control map to do
map(myEnum as {} as {[key: string]: string}? Not only is that ugly, but it doesn't protect me in the case that someone changes the shape of the enum (e.g. adding a non-string value).mhegazy commentedon Mar 27, 2018
it is unsafe, since the index signature on the enum is really
string | undefined. but i suppose we can bend the rules here the same way we do for object literals... worth discussing.appsforartists commentedon Mar 27, 2018
Thanks.
The index signature on
{a: 1, b: 2}is also reallystring|undefined, so accepting a string enum's potential for anundefinedkey feels consistent with that.dardino commentedon Mar 27, 2018
Another case with standard enums:
mhegazy commentedon Mar 27, 2018
Gabriele (@dardino) i am afraid this is a different issue. all objects can be indexed with strings/numbers and result in an
anyif not defined. it should be reported as an error under--noImplicitAny.RyanCavanaugh commentedon Aug 6, 2018
This would be super problematic because we always allow expressions of the form
expr.propnameifexprhas a string index signature, so there would be effectively zero "typo protection" onpropname. We don't want to be in the situation where removing or renaming a string enum key doesn't cause new errors to appear, or where misspelling a string enum key doesn't cause an error.royling commentedon Feb 3, 2021
This can now be easily done with the new template literal types introduced in 4.1: