user10104341
user10104341

Reputation:

TypeScript - Switch Statement based on Enum Comparison goes straight to DefaultCase

THE PROBLEM: I have a switch Statement. The comparison is based on two enums. But the conditions are all returning false.

POSSIBLE SOLUTION FOUND ON STACK_OVERFLOW: I read somewhere, that in order to avoid this, you have to put a + in the case like so:

switch(+resources) instead of switch(resources)

This has the side effect, of transforming the case in a number, which makes TS, quite unhappy since my enums are strings.

SAMPLE CODE: The enums, I want to use in my Function:

enum ResourceTypes {
  RESOURCE1 = 'RESOURCE1',
  RESOURCE2 = 'RESOURCE2',
  RESOURCE3 = 'RESOURCE2',
}

export default ResourceTypes;
enum OperationTypes {
  OPERATION1 = 'OPERATION1',
  OPERATION2 = 'OPERATION2',
  OPERATION3 = 'OPERATION3',
  OPERATION4 = 'OPERATION4'
}

export default OperationTypes;

The Function, that reverts always to the default case, is simply checking the resourceType, and returns an array of operations:

import ResourceTypes from '../enums/ResourceTypes';
import OperationTypes from '../enums/OperationTypes';

const operationPerResource = (resource: any): OperationTypes[] => {
  const { RESOURCE1, RESOURCE2, RESOURCE3 } = ResourceTypes;
  const { OPERATION1, OPERATION2, OPERATION3, OPERATION4 } = OperationTypes;

  switch (resource) {
    case RESOURCE1:
      return [OPERATION2, OPERATION3, OPERATION4];
    case RESOURCE2:
      return [OPERATION1, OPERATION2, OPERATION3];
    case RESOURCE3:
      return [OPERATION1, OPERATION2];
    default:
      return [];
  }
};

export default operationPerResource;

And this is where I call the function:

    const resources = transformEnumToArray(ResourceTypes);

    const operations = operationPerResource(resources.value).map((value: any) => ({
      label: value,
      value
    }));

This is the transofrmEnumToArray Function:

const transformEnumToArray = (object: object): any =>
  Object.keys(object).map(value => ({
    label: value,
    value
  }));

export default transformEnumToArray;

A few details on the implementation. operations is used in a React-Select Component. So, for every selection, I make on one field(Resources), I get the available Operations in another.

The resources.value, is printed in the console. I get everything back , in a label, value object, as per every react-select.


I mean, what am I doing wrong here? Why is the comparison for the enums, aren't working. Can you guys help me out here? I tested this with constants instead of enums and it works just fine. So what is the difference with enums in Typescript? Thank you

Upvotes: 0

Views: 4959

Answers (3)

user1067920
user1067920

Reputation: 1572

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

Example:

enum ResourceTypes {
    RESOURCE1 = 'RESOURCE1',
    RESOURCE2 = 'RESOURCE2',
    RESOURCE3 = 'RESOURCE2',
}

enum OperationTypes {
    OPERATION1 = 'OPERATION1',
    OPERATION2 = 'OPERATION2',
    OPERATION3 = 'OPERATION3',
    OPERATION4 = 'OPERATION4',
}

const operationPerResource = (resource: ResourceTypes): OperationTypes[] => {
    const { RESOURCE1, RESOURCE2, RESOURCE3 } = ResourceTypes;
    const { OPERATION1, OPERATION2, OPERATION3, OPERATION4 } = OperationTypes;

    switch (resource) {
        case RESOURCE1:
            return [OPERATION2, OPERATION3, OPERATION4];
        case RESOURCE2:
            return [OPERATION1, OPERATION2, OPERATION3];
        case RESOURCE3:
            return [OPERATION1, OPERATION2];
        default:
            return [];
    }
};


console.log (operationPerResource(ResourceTypes.RESOURCE2))

will compile 🥳 and output ["OPERATION1", "OPERATION2", "OPERATION3"]👍

Upvotes: 2

Adrien Martinet
Adrien Martinet

Reputation: 113

EDIT: (I can't comment your post yet)

If you check in typescript playground you can see why it works with JS object dans not enum. When you check RESOURCE1 it's not evaluated as the string RESOURCE1 you chan check that by changing RESOURCE1: 'RESOURCE123' for exemple

I don't usually work with enum neither but seems that

const { RESOURCE1, RESOURCE2, RESOURCE3 } = ResourceTypes

// RESOURCE1 != 'RESOURCE1' as it would be for a JS Object
// RESOURCE1 === RESOURCE1

You can check this playground open your console, and hit run button. If you look at cases keys, you'll see that the first one is not RESOURCE1aze but still RESOURCE1


You could still use tell don't ask pattern to avoid switch statement :

import { RESOURCE1, RESOURCE2, RESOURCE3 } from '../enums/ResourceTypes'
import { OPERATION1, OPERATION2, OPERATION3, OPERATION4 } from '../enums/OperationTypes'

const cases = {
  RESOURCE1: [OPERATION2, OPERATION3, OPERATION4],
  RESOURCE2: [OPERATION1, OPERATION2, OPERATION3],
  RESOURCE3: [OPERATION1, OPERATION2],
  default: []
}

const operationPerResource = (resource: ResourceTypes): OperationTypes[] => {
  const operations = cases[ressource] || cases['default']
  return operations
}

export default operationPerResource

Here is an exemple in the typescript playground

Upvotes: 0

Jacob Patenaude
Jacob Patenaude

Reputation: 139

Can you show example calling code? A few thoughts that might help to track down the issue:

I would expect the signature to be

const operationPerResource = (resource: ResourceType): OperationTypes[]

This will guarantee you're calling with a ResourceType

I've never seen enums destructured like that. Of course I don't think there's anything wrong with it, but it's possible that TypeScript is doing something unexpected with the types. Does anything change if you rewrite out explicitly ResourceType.RESOURCE1, etc.

Upvotes: 0

Related Questions