【问题标题】:How to check if a given string key exists in Enum?如何检查枚举中是否存在给定的字符串键?
【发布时间】:2017-03-28 15:41:57
【问题描述】:

我有一个这样定义的枚举:

export enum someEnum {
    None = <any>'',
    value1 = <any>'value1',
    value2 = <any>'value2',
    value3 = <any>'value3'   
}

例如,我想检查枚举中是否存在“value4”键。我应该得到 false 因为 value4 没有在枚举上定义。

我尝试了if (someEnum['value4']),但出现错误:

元素隐式具有“任意”类型,因为索引表达式不是“数字”类型。

【问题讨论】:

    标签: typescript enums


    【解决方案1】:

    您可以使用in 运算符:

    if ('value4' in someEnum) {
      // ...
    }
    

    【讨论】:

    • @Kingintheworld。我在下面发布了一个 TypeScript 3.7.2 的示例。
    • 如果您的值与键相同,这仅适用于基于数字的枚举或字符串枚举
    【解决方案2】:

    对于目标为 es2017 或更高版本的 TypeScript 3.7

    enum EList {
      ITEM_FOO = 'fooData',
      ITEM_BAR = 'barData'
    }
    
    const lookingForKey = 'ITEM_BAR'
    const lookingForValue = 'barData'
    
    // test if `lookingForKey` exists within `EList`
    console.log(Object.keys(EList).some((v) => v === lookingForKey))
    
    // test if `lookingForValue` exists within `EList`
    console.log(Object.values(EList).some((v) => v === lookingForValue))
    

    【讨论】:

    • 这种方法比使用in 运算符更好吗?
    • @enanone, in 运算符仅检查键,因此它仅适用于键等于值的基于数字的枚举或字符串枚举。如果枚举键与值不同,这将起作用。这是ts playground,您可以在其中进行测试
    • @ViktorZhurbin 那么我想我会尽可能地使用in(不那么冗长=更好),如果in 没有完成工作,则回退到这个解决方案
    【解决方案3】:

    Typescript 枚举有点烦人,因为它们有两个方面 - 用于命名值的原子和实际值。这些都有不同的检查方式。

    让我们使用一个示例枚举来表示内容拦截器可以执行的操作。我们将从我们的 API 中获得一个 kebab-case 值,但希望在 TS 中使用一个 camelCase 值:

    enum ActionType {
      block = "block",
      cssDisplayNone = "css-display-none",
      ignorePreviousRules = "ignore-previous-rules"
    }
    

    现在,如果我们想检查在我们的代码中说 ActionType.cssDisplayNone 是否有效,我们可以使用 in 运算符进行检查。但是,如果我们从 API 获得一个值,并且我们想查看我们得到的 是否是 ActionType,那将无法正常工作!

    const canBlockCss = 'cssDisplayNone' in ActionType; // Returns true
    const isValidAction = 'css-display-none' in ActionType; // Returns false!
    

    在这种情况下,我们需要写一个type guard

    function isActionType(test: any): test is ActionType {
        return (Object.values(ActionType).indexOf(test) !== -1);
    }
    
    const isValidAction = isActionType('css-display-none') // Returns true
    

    这有一个额外的好处,如果你有一个未知类型的变量并将它传递给类型保护,返回值将包含在 Typescript 对变量的理解中,允许你在检查的同时转换它它。

    【讨论】:

      【解决方案4】:

      要了解如何检查enum 中是否存在值,必须了解编译后它会变成什么。它只不过是一个由 IIFE(立即调用函数表达式)填充的旧 JavaScript 对象。

      假设您有一个简单的基于字符串的enum

      enum Test {
        TEST = "test"
      }
      

      编译后的 JavaScript 代码如下所示:

      var Test;
      (function (Test) {
          Test["TEST"] = "test";
      })(Test || (Test = {}));
      

      请注意,这样做的结果很简单:

      var Test = {
        "TEST": "test"
      }
      

      显然,in 运算符足以检查 enum 中是否存在密钥。如果值等于键也足够了,但只是偶然

      类型保护确实是一个更可行的解决方案,但也可以通过以下方式进行改进:

      1. 稍微优化一下 - 一个简单的 for...in 循环就可以了,在这种情况下,我们甚至可以省略 hasOwnProperty 保护。
      2. 制作类型保护 generic 以实现可重用性。

      请注意,val 参数不仅仅是T,而是T 中的一个值(因此T[keyof T]):

      function hasA<T>(obj : T, val: any) : val is T[keyof T] {
          
          for(const k in obj) {
              if( obj[k] === val ) {
                  return true;
              }
          }
          
          return false;
      };
      

      Testing 确保一切正常:

      var t = "something";
      
      if(hasA(Test,t)) {
          t //inferred as "Test"
      }
      
      var d = "any";
      
      if( !hasA(Test, d) ) {
          d //inferred as "string"
      }
      
      console.log( hasA( Test, "something" ) ); //true
      console.log( hasA(Test, "anything") ); //false
      

      【讨论】:

        【解决方案5】:

        对于基于字符串的枚举,您要检查枚举右侧的值,这是我发现的最简洁的:

        Object.values(someEnum).includes('value4')
        

        这需要 ES2017。

        【讨论】:

          猜你喜欢
          • 2020-11-29
          • 1970-01-01
          • 2011-06-23
          • 1970-01-01
          • 2012-06-03
          • 1970-01-01
          • 2015-02-12
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多