9

This statement fails. How could I cast from one enum into another (which are identical)

enum Enum1 {
  Key1 = 'key'
}

enum Enum2 {
  Key1 = 'key'
}

const key = Enum1.Key1
const key2 = key as Enum2
2
  • 1
    Can you write down a practical use case where you need to do this? It'll help us understand the problem better. Commented Mar 8, 2018 at 8:19
  • 1
    I sometimes have the same enum defined in multiple places and unable to import from one to another due to dependency boundaries. So i thought keeping them exactly the same would make TS compiler happy, but apparently not. Commented Mar 8, 2018 at 19:58

5 Answers 5

5

Here is a solution that works for number values. However, note this is "dangerous" as there is no confirmation/validation about the conversion occurring, so probably doesn't satisfy your desire for compile-time checking. The bottom line is you have to cast to some intermediate compatible type (number, string, any, unknown) before casting to 2nd enum, and by so doing, you have detached any meaningful semantic checking. Anytime you cast you are giving up compile time checking by definition.

enum SeverityLevel {
    Verbose = 0,
    Warning = 1
}

enum InternalSeverity {
    Verbose = 0,
    Warning = 1
}


function CallMe(severity: SeverityLevel) {
    console.log(`SeverityLevel: ${severity}`);
}

function Convert(severity: InternalSeverity) {
    console.log(severity);
    console.log(SeverityLevel[severity]);
    console.log(InternalSeverity[severity]);

    CallMe(severity as number as SeverityLevel);
}

Convert(InternalSeverity.Warning);

Output

It might be better to write a verbose conversion function that maps values explicitly and can check that, for example, warning is the same in both enums, like so:

switch (severity) {
   case SeverityLevel.Warning:
      return InternalSeverity.Warning;
      break;

This allows conversion between enums, is resilient to changes in the underlying values (assuming the purpose of the enum is to use names to represent values and that the values themselves are irrelevant) and satisfies compile time checks (insofar as if someone removes the key from the enum it will break). If the values are more important than the names, then you may need a slightly different approach.

Sign up to request clarification or add additional context in comments.

Comments

1

In case you use number instead of string as the enum values this would work:

enum Enum1 {
  Key1 = 2
}

enum Enum2 {
  Key1 = 2
}

const key = Enum1.Key1
const key2 = Enum2[Enum1[key]];

1 Comment

Actually, this also works for string values if enum keys and values are the same: typescriptlang.org/play?#code/…
1

You can cast to string first and then to the desired enum:

const key2 = key as string as Enum2

Comments

0

It seems indeed that Typescript doesn't bother checking the possible values, so it doesn't notice these enums are compatible. What I am doing right now is

const key2 = key as Enum1 & Enum2

It is not perfect, since it does not enforce the enum's compatibility. However still better than widening to string or any.

Comments

-1

At runtime the variable will contain the enum value (key in your case) So you can just cast through any and it should work

const key = Enum1.Key1
const key2: Enum2 = key as any

3 Comments

I understand this works at runtime. I was hoping to find a compile time safe way of doing this. (e.g. if Enum2 def changed, it should complain)
@Tony don't think there is a way to do this with enums.... maybe if you don't use enums .. I fiddled with some types that simulate enums, but allow assignment between enums if the same value exists, using string literals
Yea seems that's the workaround - string union rather than enum.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.