How to check the type is enum or not in typescript

前端 未结 4 1210
梦谈多话
梦谈多话 2021-01-23 13:23

I have a string enum type like:

export enum UserRole {
admin = "admin",
active = "active",
blocked = "blocked"
}

I

相关标签:
4条回答
  • 2021-01-23 13:35

    Javascript does not have the concept of Enum so it's not possible, When compiling, typescript translates the enum definition to normal Javascript object that you use everyday. No information about Enum is reserved for you to inspect.

    So this enum definition below

    enum UserRole {
        admin = "admin",
        active = "active",
        blocked = "blocked"
    }
    

    Will be translated to something like this

    var UserRole;
    (function (UserRole) {
        UserRole["admin"] = "admin";
        UserRole["active"] = "active";
        UserRole["blocked"] = "blocked";
    })(UserRole || (UserRole = {}));
    
    0 讨论(0)
  • 2021-01-23 13:42

    As @NearHuscarl said there is no way to check that. However you can check if djson.role (string) is one of UserRole (enum) values:

    !!(Object.values(UserRole).find(enumValue => enumValue === djson.role)));
    
    0 讨论(0)
  • 2021-01-23 13:42

    The value of an enum is either a string or number. So, they only way to test, is to test against a string or number.

    We can start by creating a User-Defined Type Guard which would look like this:

    function isInstance<T extends object>(value: string, type: T): type is T {
        return Object.values(type).includes(value)
    }
    

    This returns true or false if the value is found in the enum (This doesn't work well on numbers or enums with the same string).

    enum Animal {
        Cat = 'cat',
        Dog = 'dog'
    }
    
    enum Plant {
        Tree = 'tree',
        Flower = 'flower'
    }
    
    function isInstance<T extends object>(value: string | number, type: T): type is T {
        return Object.values(type).includes(value)
    }
    
    console.log(isInstance('dog', Animal)) // True
    console.log(isInstance('dog', Plant))  // False
    
    0 讨论(0)
  • 2021-01-23 13:58

    I usually stay away from enums because they one of those few TypeScript features that violate TypeScript's own language design goals: they are not part of JavaScript yet they compile to JavaScript. This means that we can't easily point to a JavaScript spec for what happens at runtime.


    Anyway, it seems like you are interested in the runtime behavior of enums and not necessarily their type system behavior, so in what follows I will worry about answering your question at runtime and not in the compiler. At runtime, an enum will just be an object with keys and values. And as long as you're using a string enum, the keys and values will be identical to the keys and values you set.

    (If you're using a numeric enum there will also be reverse mappings where the value is added as a key and the key is added as a value. This is extra confusing but doesn't seem to apply to your question so I'll avoid talking about it unless pressed for more details.)

    You've set the keys and values of your enum to be identical, which leads to an ambiguity I'd like to avoid. I'm going to redefine UserRole like this:

    enum UserRole {
        ADMIN = "admin",
        ACTIVE = "active",
        BLOCKED = "blocked",
    }
    

    Now we can show the difference between the question "is this string a key of the enum" and "is this string a value of the enum". Anyway, assuming we have a string role and we want to see if it's a key of the enum, we can do this:

    const roleIsEnumKey = role in UserRole;
    console.log("role " + role + (roleIsEnumKey ? " IS " : " IS NOT ") + "a key in UserRole");
    

    And if we want to see if it's a value of the enum, we can do this:

    const roleIsEnumValue = (Object.values(UserRole) as string[]).includes(role);
    console.log("role " + role + (roleIsEnumValue ? " IS " : " IS NOT ") + "a value in UserRole");
    

    assuming you are using a version of JS with Object.values() and Array.prototype.includes(). If not, you can iterate over Object.keys() or any other method you want.

    Let's see if it works:

    check(JSON.stringify({ role: "ADMIN" }));
    // role ADMIN IS a key in UserRole 
    // role ADMIN IS NOT a value in UserRole
    
    check(JSON.stringify({ role: "admin" }));
    // role admin IS NOT a key in UserRole 
    // role admin IS a value in UserRole 
    
    check(JSON.stringify({ role: "random" }));
    // role random IS NOT a key in UserRole
    // role random IS NOT a value in UserRole 
    

    Looks good. The point is, at runtime the enum is just an object, and you can check its keys and values the way you would with any object.


    Playground link

    0 讨论(0)
提交回复
热议问题