TypeScript TS7015 error when accessing an enum using a string type parameter

Typescript

Typescript Problem Overview


I am new to TypeScript and I don't understand what I need to do to fix the line that generates the TS7015 error (referencing an enum member using a string variable) because the line immediately following that does not error (referencing an enum member using a string literal):

enum State {
    Happy = 0,
    Sad = 1,
    Drunk = 2
}

function Emote(enumKey:string) {
    console.log(State[enumKey]); // error TS7015: Element implicitly has an 'any' type because index expression is not of type 'number'.
    console.log(State["Happy"]); // no error
}

"noImplicitAny": true is set in the project's tsconfig.json the error is detected

"noImplictAny": false is set in the project's tsconfig.json no error is detected

I'm compiling with "ntypescript": "^1.201603060104.1"

I'm now compiling with "tsc": "1.8.10"

C:>npm install -g typescript

`-- typescript@1.8.10

Verifying installation:

C:\>tsc --version

Version 1.8.10

Here's my tsconfig.json file:

{
  "compileOnSave": true,
  "compilerOptions": {
    "target": "ES5",
    "module": "System",
    "moduleResolution": "node",
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "removeComments": true,
    "noImplicitAny": true,
    "sourceMap": true,
    "mapRoot": "map/",
    "diagnostics": true
  },
  "exclude": [
    "node_modules",
    "typings"
  ]
}

Here's the compiler output:

C:\>tsc

test.ts(8,17): error TS7015: Element implicitly has an 'any' type because index expression is not of type 'number'.

Typescript Solutions


Solution 1 - Typescript

If you're using TypeScript 2.1+, you can change enumKey's type to keyof typeof State, like this:

function Emote(enumKey: keyof typeof State) {...}

or, if the function's input is required to be a string, this:

var state : State = State[enumKey as keyof typeof State];

Explanation:

Because enumKey is an arbitrary string, TypeScript doesn't know whether enumKey is the name of a member of State, so it generates an error. TypeScript 2.1 introduced the keyof operator which returns a union of the known, public property names of a type. Using keyof allows us to assert that the property is indeed in the target object.

However, when you create an enum, TypeScript actually produces both a type (which is typically a subtype of number) and a value (the enum object that you can reference in expressions). When you write keyof State, you're actually going to get a union of the literal property names of number. To instead get the property names of the enum object, you can use keyof typeof State.

Sources:

https://github.com/Microsoft/TypeScript/issues/13775#issuecomment-276381229 https://www.typescriptlang.org/docs/handbook/enums.html#enums-at-compile-time

Solution 2 - Typescript

I suspect it has to do with TS 1.8.x's new support for string literals in these situations. TS happens to know that "Happy" is a valid string index, but it doesn't know whether enumKey will be or not. You can fix it by casting it to an <any>, like so:

function Emote(enumKey:string) {
    console.log(State[enumKey]); // error TS7015: Element implicitly has an 'any' type because index expression is not of type 'number'.
    console.log(State["Melancholy"]); // error TS7015: Element implicitly has an 'any' type because index expression is not of type 'number'.
    console.log(State["Happy"]); // no error
    console.log(State[<any>enumKey]); // no error
    console.log(State[<any>"Melancholy"]); // no error
}

(BTW, I think this is new: I couldn't reproduce this error with 1.8.9, but as soon as I upgraded to 1.8.10, I could.)

Also interestingly, I would have expected this to work without the error, but it doesn't:

function TypedEmote(enumKey:'Happy'|'Sad'|'Drunk'){
    console.log(State[enumKey]);
}

Must be something about the TS spec I don't understand, or perhaps they just haven't gotten around to fixing that bit yet.

Solution 3 - Typescript

You can prevent this error with the compiler option without loosing the whole strict null checks

"suppressImplicitAnyIndexErrors": true

https://www.typescriptlang.org/tsconfig#suppressImplicitAnyIndexErrors

Solution 4 - Typescript

var stateName = "Happy"
var state = <State>parseInt(State[<any>stateName]);

This is what I had to do to make the compiler happy

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionNeoheuristView Question on Stackoverflow
Solution 1 - TypescriptSteven BarnettView Answer on Stackoverflow
Solution 2 - TypescriptKen SmithView Answer on Stackoverflow
Solution 3 - TypescriptHolgerJerominView Answer on Stackoverflow
Solution 4 - TypescriptSharpiroView Answer on Stackoverflow