Typescript enum switch going to default instead of proper case
Asked Answered
R

13

108

I have the following enum:

enum EditMode {
    View = 0,
    Edit = 1,
    Delete = 2
}

Let's assume I have a variable of the enum type

var editMode = EditMode.Edit;

Why does the following code not work (goes straight to default)?

switch (editMode) {
    case EditMode.Delete:
        // ...
        break;
    case EditMode.Edit:
        // ...
        break;
    default:
        // ...
        break;
}
Resolve answered 2/1, 2015 at 19:22 Comment(5)
This code works in the TypeScript Playground. Are you sure your scripts are loading in the correct order?Haydeehayden
I can also confirm it works in the Playground.Hecht
yes it does, it seems the issue is not the code itself. for some reason my code assigns not a number behind the enum but the string associated with the number eg istead of 1 (Edit) "1". why i can't understand.Resolve
Replace it with if/else and it should work. There are a bunch of typing issues/features in TypeScript. Eg. that one - github.com/Microsoft/TypeScript/issues/8618Orientation
Actually this code is NOT working in the Typescript playground... editmode DELETE is not comparable to editmode EDITNick
R
29

I have found why this happens: somewhere in the code there is a activation function (I am using durandal) which passes this enum as a string (the function has the parameter marked as a enum but still it is a string). This is why my switch statement fails.

I simply converted the value to a number and now everything works as expected.

Resolve answered 2/1, 2015 at 20:0 Comment(1)
This was the problem for me as well. My constructor had a parameter of type Enum, but an outside caller was passing a string. I changed the constructor parameter to be of type string, and used EnumType[parameter] to convert it to the enum.Filature
S
120

I also had this problem. Easy way to get around it: add a + sign before your variable in the switch, i.e.

switch (+editMode) {
    case EditMode.Delete:
        ...
        break;
    case EditMode.Edit:
        ...
        break;
    default:
        ...
        break;
    }
Speiss answered 3/4, 2017 at 7:26 Comment(3)
This seems the only way to fix the typescript glitch / bug.Nick
So the + will change it to a number, and that seems to work. I think this does not seem like a great solution. I also tried assigning the first item to 0 in my enum and it did not help. Seems like a bug.Cicatrize
+ is a hack that coerces it to a number. My answer below is correct based on modern Typescript version.Unicycle
R
29

I have found why this happens: somewhere in the code there is a activation function (I am using durandal) which passes this enum as a string (the function has the parameter marked as a enum but still it is a string). This is why my switch statement fails.

I simply converted the value to a number and now everything works as expected.

Resolve answered 2/1, 2015 at 20:0 Comment(1)
This was the problem for me as well. My constructor had a parameter of type Enum, but an outside caller was passing a string. I changed the constructor parameter to be of type string, and used EnumType[parameter] to convert it to the enum.Filature
H
22

The issue here has to do with typescript's (numeric) literal types. When you do this assignment:

var editMode = EditMode.Edit

TypeScript evaluates the type as:

var editMode: 1 = EditMode.Edit

Now, when you compare a value that typescript knows must be 1 (EditMode.Edit) to a value that it knows must be 0 (EditMode.View), it sees all this as a type-safety violation. If the variable editMode weren't an enum, typescript would merely complain, but since it's an enum, which doesn't really exist in javascript, typescript gets to control the transpilation in such a way that it actually throws an error.
So you have 2 options. So you can either coerce editMode to be a number or to be an EditMode (i.e. any of the values EditMode is permitted to be, not just the one assigned to editMode the variable).
Personally, I prefer to coerce it to be an EditMode, because it feels more type-safe.

To go the number route, you can do the following, which was previously mentioned:

switch(+editMode)

To go the EditMode route (which I recommend), you can pass it to a function as was mentioned, but sometimes it's a little cleaner to not write a function. If that's the case here, then you can again coerce the type in the switch statement:

switch(editMode as EditMode)

Do whichever you prefer, but I just like the clarity of explicitly saying "this variable is being treated as an EditMode" as opposed to "this variable is supposed to actually be a number, not an Enum".

Hindsight answered 20/1, 2020 at 22:8 Comment(0)
U
15

Change your EditMode enum definition to:

enum EditMode {
    View = "View",
    Edit = "Edit",
    Delete = "Delete"
}
Unicycle answered 6/12, 2019 at 17:42 Comment(2)
This worked for me better than the integer-based solutions, because my objects were coming in from a REST service that served a JSON where the enum values where text values, thus I couldn't assign numbers to them or I would break the serialization/deserialization process.Tierney
This is proper answerBogeyman
P
12

TypeScript version 3.7.5

this code worked for me

enum Seasons {
    Winter,
    Spring,
    Summer,
    Autum
  }

switch (+Seasons.Winter) {
    case Seasons.Winter:
        console.log('weather is cold');
        break;
    case Seasons.Spring:
        console.log('weather is spring');
        break;
    case Seasons.Summer:
        console.log('weather is summer');
        break;
    default:
        break;
}

visual studio code: seasons

or you can declare a constant and use as param for switch statement

const season: Seasons = Seasons.Winter
switch (+season) {
    case Seasons.Winter:
        console.log('weather is cold');
        break;
    case Seasons.Spring:
        console.log('weather is spring');
        break;
    case Seasons.Summer:
        console.log('weather is summer');
        break;
    default:
        break;
}

enter image description here

Pectize answered 2/1, 2015 at 19:23 Comment(2)
it doesn't work without the plus ('+'). how come it solves the problem?Caliper
d***, life saver. any documentation?Paid
C
3

In case somebody else ends up here and the above options don't seem to be the issue, double-check that all of your switch statements are breaking/returning! The Typescript compiler is smart enough to see that if your case cascades through to another one, the value you're comparing on may never hit the case you expect.

let handlerName;

switch(method){
  case 'create':
    handlerName = 'createHandler';
    break;
  case 'update';
    handlerName = 'updateHandler';
    // Here is where the forgotten break would go
  default:
    throw new Error('Unrecognized Method');
}

switch(handlerName){
  case 'createHandler':
    ...
    break;
  case 'updateHandler':
    // You will see an error on this case because
    // the compiler knows that execution will never
    // arrive here with handler === 'updateHandler'
  default:
    throw new Error('Unrecognized Handler');
}
Commercial answered 3/7, 2019 at 18:42 Comment(0)
S
2

With //@ts-ignore suppress you can do:

//@ts-ignore
switch (EditMode[editMode] as EditMode) {
    case EditMode.Delete:
        ...
        break;
    case EditMode.Edit:
        ...
        break;
    default:
        ...
        break;
    }
}
Serrate answered 21/10, 2020 at 12:28 Comment(1)
While this works, it's unwise to @ts-ignore all your problems away. TS is there to help you write type-safe code to avoid headache down the line. Though ignore this advice if TS itself has a bug and you have to rely on it to deploy.Warlord
C
1

If the enum is defined in a separate typescript file, ensure it's marked with "export" and that you import it correctly at the top of the typescript file you're referencing it in.

Cornerwise answered 13/5, 2020 at 8:59 Comment(0)
B
1

Use it like this.

const enum OperationsType{
    CREATE="CREATE",
    DELETE="DELETE",
    UPDATE="UPDATE"
}
Blinny answered 13/10, 2020 at 11:37 Comment(0)
B
1

Int Enum

    enum Sizes {
      Small,
      Medium,
    }
    
    switch (Number(Sizes.Small)) {
      case Sizes.Small:
       

 // 👇️ this runs
    console.log('size is S');
    break;
  case Sizes.Medium:
    console.log('size is M');
    break;

  default:
    console.log(`non-existent size: ${Sizes.Small}`);
    break;
}

String Enum

enum Sizes {
      Small = 'S',
      Medium = 'M',
    }
    
    switch (String(Sizes.Small)) {
      case Sizes.Small:
        console.log('size is S');
        break;
      case Sizes.Medium:
        console.log('size is M');
        break;
    
      default:
        console.log(`non-existent size: ${Sizes.Small}`);
        break;
    }
Busman answered 20/2, 2023 at 8:56 Comment(0)
M
-1

Declare your enum using const:

const enum EditMode {
    View = 0,
    Edit = 1,
    Delete = 2
}
Mousetrap answered 27/5, 2019 at 4:28 Comment(2)
This does not fix it for me.Offside
This will work on versions 3.0 and older but not on newer versions.Bohol
A
-1

In my case I had the switch inside a condition, which was coercing the enum into a value:

enum A {
    VAL_A,
    VAL_B,
    VAL_C
}
interface ia {
    maybe?: A
}
const o: ia = {maybe: 0}
if(o.maybe){ //<-- o.maybe is not falsey (thus, is not 0)
    switch(o.maybe) {
        case A.VAL_A: //<-- Error! we know that o.maybe is not 0. Its VAL_B | VAL_C
        break;
    }

}

Acceptance answered 3/4, 2020 at 10:12 Comment(0)
M
-2

If you use the switch expression in a function with typed parameter, this works as expected.

Example:

enum EditMode {
    View,
    Edit,
    Delete,
}

function testSwitch(editMode: EditMode) {
    switch(editMode) {
        case EditMode.Delete:
            console.log("delete");
            break;
        case EditMode.Edit:
            console.log("edit");
            break;
        default:
            console.log("default");
            break;
    }
}

testSwitch(EditMode.Edit)

will compile 🥳 and output edit 👍

Museum answered 15/1, 2020 at 10:16 Comment(1)
This will work on version 3.0 in typescript but not on later version.Bohol

© 2022 - 2024 — McMap. All rights reserved.