【问题标题】:How to check the type is enum or not in typescript如何在打字稿中检查类型是否为枚举
【发布时间】:2020-12-24 11:20:29
【问题描述】:

我有一个字符串枚举类型,例如:

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

我想检查某个字符串是emule还是不是怎么做?

  const djson = JSON.parse(decode_string)
  if(djson && (djson.role instanceof UserRole) // I just want to check the role is enum string or not. Obviously  this way is wrong.

怎么做?

【问题讨论】:

    标签: typescript oop enums


    【解决方案1】:

    enum 的值可以是字符串或数字。因此,他们唯一的测试方法是针对字符串或数字进行测试。

    我们可以从创建一个如下所示的User-Defined Type Guard 开始:

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

    如果在枚举中找到值,则返回真或假(这不适用于具有相同字符串的数字或枚举)。

    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
    

    【讨论】:

      【解决方案2】:

      我通常远离 enums,因为它们是少数几个违反 TypeScript's own language design goals 的 TypeScript 功能之一:它们不是 JavaScript 的一部分,但它们编译为 JavaScript。这意味着我们不能轻易地指出运行时发生的事情的 JavaScript 规范。


      无论如何,您似乎对enums 的运行时行为感兴趣,而不一定对它们的类​​型系统行为感兴趣,所以接下来我会担心在运行时而不是在编译器中回答您的问题。在运行时,enum 将只是一个带有键和值的对象。只要您使用string enum,键和值将与您设置的键和值相同。

      (如果您使用的是numeric enum,那么还会有reverse mappings,其中值作为键添加,键作为值添加。这更加令人困惑,但似乎不适用于您的问题,所以我会避免谈论它,除非被要求了解更多细节。)

      您已将 enum 的键和值设置为相同,这会导致我想避免歧义。我要像这样重新定义UserRole

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

      现在我们可以说明问题“这个字符串是枚举的键吗”和“这个字符串是枚举的值”之间的区别。无论如何,假设我们有一个字符串 role 并且我们想看看它是否是枚举的键,我们可以这样做:

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

      如果我们想查看它是否是枚举的值,我们可以这样做:

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

      假设您使用的是带有Object.values()Array.prototype.includes() 的JS 版本。如果没有,您可以遍历 Object.keys() 或您想要的任何其他方法。

      让我们看看它是否有效:

      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 
      

      看起来不错。关键是,在运行时 enum 只是一个对象,您可以像使用任何对象一样检查它的键和值。


      Playground link

      【讨论】:

        【解决方案3】:

        正如@NearHuscarl 所说,没有办法检查。 但是,您可以检查 djson.role (string) 是否是 UserRole (enum) 值之一:

        !!(Object.values(UserRole).find(enumValue => enumValue === djson.role)));
        

        【讨论】:

          【解决方案4】:

          Javascript 没有 Enum 的概念,所以不可能,在编译时,typescript 会将 enum 定义转换为您日常使用的普通 Javascript 对象。没有保留有关 Enum 的信息供您检查。

          所以下面这个枚举定义

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

          会被翻译成这样的

          var UserRole;
          (function (UserRole) {
              UserRole["admin"] = "admin";
              UserRole["active"] = "active";
              UserRole["blocked"] = "blocked";
          })(UserRole || (UserRole = {}));
          

          【讨论】:

            猜你喜欢
            • 2020-09-02
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2019-05-26
            • 1970-01-01
            • 2019-07-09
            • 2011-12-24
            • 2017-03-09
            相关资源
            最近更新 更多