【问题标题】:How to compare Enums in TypeScript如何比较 TypeScript 中的枚举
【发布时间】:2017-02-08 15:59:00
【问题描述】:

在 TypeScript 中,我想比较两个包含枚举值的变量。这是我的最小代码示例:

enum E {
  A,
  B
}

let e1: E = E.A
let e2: E = E.B

if (e1 === e2) {
  console.log("equal")
}

使用tsc (v 2.0.3) 编译时出现以下错误:

TS2365:运算符“===”不能应用于类型“E.A”和“E.B”。

==!==!= 相同。 我尝试添加 const 关键字,但这似乎没有效果。 TypeScript spec 表示以下内容:

4.19.3 、=、==、!=、=== 和 !== 运算符

这些运算符要求一种或两种操作数类型可分配给另一种。结果始终是布尔原始类型。

这(我认为)解释了错误。但是我怎样才能绕过它呢?

旁注
我正在使用带有atom-typescript 的Atom 编辑器,并且我的编辑器中没有任何错误/警告。但是当我在同一目录中运行tsc 时,我得到了上面的错误。我以为他们应该使用相同的 tsconfig.json 文件,但显然情况并非如此。

【问题讨论】:

    标签: typescript enums compare equality


    【解决方案1】:

    好吧,我想我找到了一些可行的方法:

    if (e1.valueOf() === e2.valueOf()) {
      console.log("equal")
    }
    

    但我有点惊讶的是,文档中的任何地方都没有提到这一点。

    【讨论】:

      【解决方案2】:

      还有另一种方式:如果您不希望生成的 javascript 代码受到任何影响,您可以使用类型转换:

      let e1: E = E.A
      let e2: E = E.B
      
      
      if (e1 as E === e2 as E) {
        console.log("equal")
      }
      

      一般来说,这是由基于控制流的类型推断引起的。使用当前的 typescript 实现,只要涉及函数调用,它就会关闭,因此您也可以这样做:

      let id = a => a
      
      let e1: E = id(E.A)
      let e2: E = id(E.B)
      
      if (e1 === e2) {
        console.log('equal');
      }
      

      奇怪的是,如果 id 函数被声明为返回与其 agument 完全相同的类型,仍然没有错误:

      function id<T>(t: T): T { return t; }
      

      【讨论】:

        【解决方案3】:

        如果能够用这个比较两个枚举

         if (product.ProductType && 
               (product.ProductType.toString() == ProductTypes[ProductTypes.Merchandises])) {
              // yes this item is of merchandises
          } 
        

        ProductTypes 是 export enum ProductTypes{Merchandises,Goods,...}

        【讨论】:

          【解决方案4】:

          我会像这样定义 Enum 的值并与 === 进行比较

          const enum AnimalInfo {
          Tiger = "Tiger",
          Lion = "Lion"
          }
          
          let tigerStr = "Tiger";
          
          if (tigerStr === AnimalInfo.Tiger) {
            console.log('true');
          } else {
            console.log('false');
          }
          

          【讨论】:

          • 使用let tigerStr = "Tiger"; 破坏枚举概念。
          • 是的,但是tigerStr 可能是从数据库中加载的,因此将其与枚举值进行比较是非常有意义的。
          • 同意@FabioLor,不仅是数据库案例,还有几个数据源,将一个值与枚举进行比较是正常的。我不知道为什么其他评论中的赞成票比这个哈哈更多
          【解决方案5】:

          唯一对我有用的东西(在 typescript 2.2.1 中)是这样的:

          if (E[e1] === E[e2]) {
            console.log("equal")
          }
          

          这会比较表示名称的字符串(例如“A”和“B”)。

          【讨论】:

          • 最简洁的表示法,仍然可以安全输入。
          【解决方案6】:

          将枚举类型转换为字符串是一种非常有价值的技术。

          例如;

          if (String(e1) === String(e2)) {
              console.log("equal, now actually works!")
          }
          

          【讨论】:

            【解决方案7】:

            在打字稿中一个示例枚举:

            enum Example {
               type1,
               type2
            };
            

            转成javascript成这个对象:

            Example {
                '0': 'type1', 'type1': 0,
                '1': 'type2', 'type2': 1
            }
            

            我在打字稿中比较枚举时遇到了很多问题。这个简单的脚本解决了这个问题:

            enum Example {
                type1 = 'type1',
                type2 = 'type2'
            };
            

            然后在javascript中,对象被转化为:

            Example {
                'type1': 'type1',
                'type2': 'type2'
            }
            

            如果您不需要使用枚举 - 最好不要使用。 Typescript 有更高级的类型,这里有更多: https://www.typescriptlang.org/docs/handbook/advanced-types.html 你可以改用:

            type Example = 'type1' | 'type2';
            

            【讨论】:

            • 最后一个例子救了我。似乎这是实现枚举类行为的惯用 TS 方式。仍然很遗憾 TS 仍然必须有这些不健全的……怪癖?
            【解决方案8】:

            抛出错误是因为编译器意识到该语句总是错误的,因此是多余的。您声明两个明显不相等的变量,然后尝试查看它们是否相等。

            如果您将其更改为例如:

            enum E {
              A,
              B
            }
            
            foo() {
              let e1: E = E.A
              let e2: E
              e2 = bar();
            
              if (e1 === e2) {
                console.log("equal")
              }
            }
            
            bar(): E {
              return E.B
            }
            

            它应该编译没有错误。

            在旁注中,某事。喜欢

            let e1 = E.A;
            if (e1 && e1 === E.B) {
              ...
            }
            

            也不会编译,因为 e1 在这种情况下是 0 (因为 A 是第一个枚举“选项”),因此 false 这意味着永远不会达到第二个状态(不管第二个状态是否在这种情况下,声明甚至是有效的)

            【讨论】:

            • 我认为e2 = foo(),应该是e2 = bar()。我已尝试将其作为编辑发送,但似乎有更多人将其发送。对于挖掘这个旧答案,我深表歉意。
            【解决方案9】:

            原 8 月 18 日

            在我的情况下,上述解决方案都不起作用,原因是我将枚举值转换为枚举对象。

            在那之后我试图知道枚举是否等同于另一个枚举对象...所以我创建了以下 通用 函数:

              public static enumEquals<T>(e: any, e1: T, e2: T): boolean {
                const v1 = this.enumValue(e, e1);
                return v1 === this.enumValue(e, e2, typeof v1);
              }
            
              private static enumValue<T>(enumType: any, value: T, validType?: string) {
                let v = enumType[value];
                if (!validType) {
                  return v;
                }
                while (typeof v !== validType) {
                  v = enumType[v];
                }
                return v;
              }
            

            这是我的测试用例的一个例子:

            enum SomeEnum {
              VALUE1, VALUE2, VALUE3, VALUE_DEF
            }
            
            const enumRefKey = localStorage.getItem('someKey');
            const parsedEnum = SomeEnum[enumRefKey] || SomeEnum.VALUE_DEF;
            console.log(parsedEnum);
            if (parsedEnum === SomeEnum.VALUE_DEF) {
              // do stuff
            }
            

            显然代码不起作用,在我尝试了这里给出的解决方案后,我发现当 enumRefKey 有效时 console.log(parsedEnum) 正在打印数字并且文本 VALUE_DEF 不是。使用所有其他解决方案也会出现相同的结果:

            • parsedEnum 为 SomeEnum
            • parsedEnum.valueOf()
            • SomeEnum[parsedEnum]

            使用泛型方法的解决方案如下所示:

            enum SomeEnum {
              VALUE1, VALUE2, VALUE3, VALUE_DEF
            }
            
            const enumRefKey = localStorage.getItem('someKey');
            const parsedEnum = SomeEnum[enumRefKey] || SomeEnum.VALUE_DEF;
            console.log(parsedEnum);
            if (this.enumEquals(SomeEnum, parsedEnum, SomeEnum.VALUE_DEF) {
              // do stuff
            }
            

            更新 SEP/21

            TypeScript 比较中避免与enums 相关的所有问题的最佳方法是像以下示例一样声明它们。

            而不是这个:

            enum SomeEnum {
              VALUE1, VALUE2, VALUE3
            }
            

            这样做:

            enum SomeEnum {
              VALUE1 = 'VALUE1', VALUE2 = 'VALUE2', VALUE3 = 'VALUE3'
            }
            

            从现在开始,您无需将枚举值强制转换或转换为枚举对象,并且如果您需要,它将始终有效。使用此解决方案,以下所有示例均有效,它们将返回 true

            console.log(SomeEnum['VALUE1'] === 'VALUE1');             // prints 'true'
            console.log(SomeEnum['VALUE1'] === SomeEnum.VALUE1);      // prints 'true'
            console.log(SomeEnum['VALUE1'] === 'VALUE1' as SomeEnum); // prints 'true'
            console.log(SomeEnum['VALUE1'] === 'VALUE1');             // prints 'true'
            console.log(SomeEnum['VALUE1'] === (<SomeEnum>'VALUE1')); // prints 'true'
            console.log(SomeEnum.VALUE1 === 'VALUE1' as SomeEnum);    // prints 'true'
            console.log(SomeEnum.VALUE1 === (<SomeEnum>'VALUE1'));    // prints 'true'
            console.log(SomeEnum.VALUE1 === 'VALUE1');                // prints 'true'
            

            罪魁祸首

            所有这些问题的原因是当TypeScript被编译为JavaScript时,枚举被解析为objects这样

            // this enum at TS
            enum SomeEnum {
              VALUE1, VALUE2, VALUE3
            }
            // is parsed to JS like this:
            {
              VALUE1: 1, VALUE2: 2, VALUE3: 3, 1: 'VALUE1', 2: 'VALUE2', 3: 'VALUE3'
            } 
            

            如您所见,一旦枚举被解析为 JS,所有比较问题的原因就很明显了,因为我们可能会错误地将 stringnumber 进行比较,这可能会导致误报结果。以下是解析为 JS 的第二个枚举,效果更好:

            // this enum at TS
            enum SomeEnum {
              VALUE1 = 'VALUE1', VALUE2 = 'VALUE2', VALUE3 = 'VALUE3'
            }
            // is parsed to JS like this:
            {
              'VALUE1': 'VALUE1', 'VALUE2': 'VALUE2', 'VALUE3': 'VALUE3'
            } 
            

            【讨论】:

              猜你喜欢
              • 2017-01-09
              • 1970-01-01
              • 2014-03-15
              • 1970-01-01
              • 2012-05-04
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2018-01-14
              相关资源
              最近更新 更多