3

I have a function which accepts an argument which has type of a few different enums in typescript. I want to check which enum type does an argument have. Is it even possible to check? Here is an example code:

enum X {
    ONE,
    TWO
}

enum Y {
    THREE,
    FOUR
}

function check(arg1: X | Y) {
    if (arg1 is X) {
        // do something with X
    }
    if (arg1 is Y) {
        // do something with Y
    }
}
iamawebgeek
  • 2,713
  • 1
  • 18
  • 34

3 Answers3

3

You could use an enum type guard function as in

Generic enum type guard

In this case:

enum X {
    ONE,
    TWO
}

enum Y {
    THREE = 3,
    FOUR
}

const isSomeEnum = <T>(e: T) => (token: any): token is T[keyof T] =>
    (Object as any).values(e).includes(token as T[keyof T]);

function check(arg1: X | Y) {
    if (isSomeEnum(X)(arg1)) {
        console.log('Arg is X')
    }
    if (isSomeEnum(Y)(arg1)) {
        console.log('Arg is Y')
    }
}

check(X.ONE)
check(Y.THREE)
check(X.TWO)
check(Y.FOUR)

To make this work you need to make sure that the enum values do not overlap, which is why you need to include 'THREE = 3' in the definition of Y.

1

When you describe a variable using an enum type (e.g., let value: X = X.ONE) that variable expects a value of one of the enum's properties but not the enum itself. The main idea of an enum is to document and reuse a group of values (e.g., enum Colors {BLUE: '#0000ff', YELLOW: '#ffff00'}). So, if you describe a variable using the Colors enum, the variable would accept either Colors.BLUE or Colors.YELLOW which resolve to an actual value of a color (e.g., '#0000ff'); so that variable won't be able to hold the Colors enum itself, just the enum's values.

Enums remain in the compiled code as objects. For example, enums X and Y in your example turn into the following objects:

var X = { '0': 'ONE', '1': 'TWO', ONE: 0, TWO: 1 }
var Y = { '0': 'THREE', '1': 'FOUR', THREE: 0, FOUR: 1 }

In your function, arg1 will contain a value of one of these enums, that is either 0 or 1. So, in your example, you will be able to check whether arg1 belongs to one of these objects (e.g., X[arg1] !== undefined), but you won't be able to guarantee that arg1 belongs to only X or only Y, because both X and Y at some point may contain same keys and or values (e.g., both will have the key 'ONE').

So, we need to make decisions based on value comparisons, like this:

if (arg1 === X.ONE) {
  // do something
}

if (arg2 === Y.THREE) {
  // do something
}

or by checking whether a value belongs to a particular enum object:

if (X[arg1] !== undefined) {
  // do something
}

if (Y[arg1] !== undefined) {
  // do something
}

There is no TS feature that checks whether a value belongs to a particular enum exclusively.

Dmytro
  • 101
  • 3
0

Not possible. Do not forget that

Enums are one of the few features TypeScript has which is not a type-level extension of JavaScript.

Enums allow a developer to define a set of named constants. Using enums can make it easier to document intent, or create a set of distinct cases. TypeScript provides both numeric and string-based enums.

https://www.typescriptlang.org/docs/handbook/enums.html

In your example: X.ONE = Y.THREE = 0, X.TWO = Y.FOUR = 1

HTN
  • 3,388
  • 1
  • 8
  • 18