Skip to content

Enum value lookup by string variable should be typed as the enum type. #592

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

Closed
marcind opened this issue Sep 3, 2014 · 10 comments
Closed
Labels
By Design Deprecated - use "Working as Intended" or "Design Limitation" instead

Comments

@marcind
Copy link

marcind commented Sep 3, 2014

I'm trying to map a value in a JSON blob that is serialized as a string to application logic code in TypeScript where the value is logically one of a set of values (and then map that back to JSON as a string to send back to a server). Naturally this maps quite well to enums. However, the type of enum value lookups via string variables is inferred as any whereas I would expect it to be the type of the enum. Here's an example:

enum Letter {
    A,
    B
}

var apiModel: { letter: string } = JSON.parse("{'letter':'A'}");
var deserialized = Letter[apiModel.letter]; // Expect inferred type as Letter, but inferred as any
var notALetter: boolean = deserialized; // This should not compile, but it does

I propose that a change be made so that member access of an enum 'type' via a variable typed as string should be an expression with a value that is that enum 'type'.

Some more examples of what I would expect

enum Letter {
    A,
    B
}

var n = 1;
var s = "A";

var fromN = Letter[n]; // Inferred string - as expected
var fromConst = Letter["A"] // Inferred Letter - as expected
var fromS = Letter[s]; // Inferred any - would expect Letter

var numberFromN: number = Letter[n]; // Fails to compile as expected
var numberFromS: number = Letter[s]; // Compiles fine as expected

var letterFromN: Letter = Letter[n]; // Fails to compile as expected
var letterFromS: Letter = Letter[s]; // Compiles fine as expected

var boolFromN: boolean = Letter[n]; // Fails to compile as expected
var boolFromS: boolean = Letter[s]; // Compiles fine - would expect failure

var stringFromN: string = Letter[n]; // Compiles fine as expected
var stringFromS: string = Letter[s]; // Compiles fine - would expect failure
@RyanCavanaugh
Copy link
Member

We don't do this on purpose because of this:

var s = "1";
var fromS = Letter[s]; // Runtime value is string, not Letter

If you really actually know that the value you're indexing with is a string key in the enum, use a type assertion.

@danquirk
Copy link
Member

danquirk commented Sep 3, 2014

Additionally, the way we would enforce this kind of constraint in the type system would be by giving enum's an implicit string indexer that returns the enum type. But this would make it very difficult to add additional members to the enum via a merged module.

@masaeedu
Copy link
Contributor

@RyanCavanaugh Now that we have string literal types and union types, couldn't this be improved somewhat?

@RyanCavanaugh
Copy link
Member

@masaeedu which parts specifically?

@masaeedu
Copy link
Contributor

Just spitballing here, but maybe you could automatically generate a union string literal type composed of all the entries in the enum. Any string assignable to that type produces a number, any other string produces any.

@RyanCavanaugh
Copy link
Member

You're aware that Letter['A'] is already of type number, right?

@RyanCavanaugh
Copy link
Member

Or you're talking about the case where you have var x: 'A' | 'B' and you're indexing by that?

@masaeedu
Copy link
Contributor

@RyanCavanaugh Yeah, that one. That lets users dynamically pick the string, but still get the correct type.

@masaeedu
Copy link
Contributor

Low priority, I know, but if you think it has a shot I could open an issue and attempt a PR.

@RyanCavanaugh
Copy link
Member

I think we're already tracking this (essentially) at #6080.

Instead of special-casing enums, we can just say that indexing x by "A"|"B" produces the type of x["A"]|x["B"], which each subcomponent gets the special behavior that you get the actual property type if the properties x.A / x.B exist

@microsoft microsoft locked and limited conversation to collaborators Jun 18, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
By Design Deprecated - use "Working as Intended" or "Design Limitation" instead
Projects
None yet
Development

No branches or pull requests

4 participants