-
Notifications
You must be signed in to change notification settings - Fork 12.5k
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
Assign string literals to string enum type #17690
Comments
The value of the enum should |
@Knagis I think the OP is trying to point out that while the above doesn't work, the following does: enum Colors {
Red = 1,
Green = 2,
Blue = 3,
}
const c1: Colors = Colors.Red;
const c2: Colors = 1; It is an incongruence in the language. |
@kitsonk I mainly pointed out that OP was using the wrong constant. It still does not let assign even with the correct one though. However in your example, unfortunately this also compiles: |
Thank you @Knagis. You're right that I used the wrong constant and I corrected my original post. |
The intent of string enums is that the values of the enum are opaque (i.e. they can be changed behind the scenes without breaking consumers). If you don't want that behavior, it's easy enough to use the pre-string-enum workarounds to create similar union types. Numeric enums allow assignments from arbitrary Why don't |
Thanks for the explanation @RyanCavanaugh! Can you point me to some documentation for the best practice workarounds from pre-string-enums? I'm currently using namespaces (https://github.com/vega/vega-lite/blob/6ea812df890070f4cc7f72ac3efc96eaa44a8c4e/src/type.ts#L4) because @DanielRosenwasser suggested it to me last year. However, with this suggestion I have a namespace and a type with the same name if I want to use string literals and constants at the same time. |
I recommend this approach: #3192 (comment) |
Even though string-based enums are now in TypeScript 2.4, it still is not possible to assign a literal string to an string-based enum (even though the value of the literal string matches a value of the enum). See the OPs example in TypeScript Playground. It still fails on the following line:
The example of OP is exactly the behavior I'd like to see: string literals and enum values being used interchangeably. It is however not yet possible. Taking it a step further, the following should work as well:
Should a new issue be created or can we reopen this one? |
@bobvanderlinden this is the intended behavior, not a bug. String enum values are intentionally opaque to consumers; if you want a non-opaque string type, you should use a literal union (i.e. |
@RyanCavanaugh Thanks for your reply. I guess we'll have to discuss some more on swagger-codegen which of the two to use (enums or unions). |
@RyanCavanaugh IMO that's a limitation in the intended behavior that restricts the usage of string enums unnecessarily. Consider how InversifyJS uses a literal union to specify settings. Because the existing behavior is to take in a string for some settings, the only way consumers can specify them in a type-safe manner is with string literals: const container = new Container({
defaultScope: "Singleton",
}); ...but that means we can't use slightly-easier-to-get-intellisense-for enum members: const container = new Container({
defaultScope: BindingScope.Singleton,
}); Does that change your opinion? Relevant issue: inversify/InversifyJS#706 |
There's already a syntax available to you for that: exported consts in namespaces namespace BindingScope {
export const Singleton: "Singleton" = "Singleton";
} |
That does work: type BindingScope = "Singleton" | "Transient" | "Request";
namespace BindingScope {
export const Singleton: "Singleton" = "Singleton";
export const Transient: "Transient" = "Transient";
export const Request: "Request" = "Request";
} const testName = (_: BindingScope) => _;
testName("Singleton");
testName(BindingScope.Singleton); ...but it's ugly and uses the discouraged |
The entire point of string enums was to provide for a way to represent opaque string types because there's existing syntax to provide non-opaque string types. If you don't want to use const BindingScope: {
Singleton: "Singleton"
} =
/* advantage: copy-paste from above 🙄 */
{
Singleton: "Singleton"
} |
The string enum in typescript differs from many other languages. When having a java-server and a REST API (JSON) with a typescript written frontend this is quite a pain. +1 for make the ability to reverse map from a value and get the key, something like Colors["Red] will get RED. |
enum Colors {
red = "reddish",
blue = "bloo",
green = "green"
}
function keyFromValue(stringEnum: { [key: string]: string }, value: string): string | undefined {
for (const k of Object.keys(stringEnum)) {
if (stringEnum[k] === value) return k;
}
return undefined;
} |
@RyanCavanaugh Yes i know, I have done exactly that solution as you suggest, but I think this is a hack because a string enum does not work both ways which I think is strange behavior where many other langugaes works different. I did it like this: |
If the string enum worked both ways, you'd have no way to tell keys from values. Presumably you want |
Some kind of valueOf is what I'm seeking for |
There's always this pattern:
However it would be useful if we had a modifier to allow permissive string enum types.
|
TypeScript Version: 2.4.0
Code
Expected behavior:
I'd expect both lines with
c1
andc2
to work but only the first compiles.Actual behavior:
The text was updated successfully, but these errors were encountered: