如何在TypeScript中比较枚举

f45qwnt8  于 2023-05-08  发布在  TypeScript
关注(0)|答案(9)|浏览(158)

在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)编译时,我得到以下错误:
TS 2365:运算符“===”不能应用于类型“E.A”和“E. B”。
==!==!=也是如此。我尝试添加const关键字,但似乎没有效果。TypeScript规范说明如下:

4.19.3 <,>,<=,>=,==,!=,===,还有!==运算符

这些运算符要求一个或两个操作数类型可赋值给另一个。结果始终为布尔基元类型。
我认为这是一个错误的解释。但我怎么能绕过它呢?

旁注

我正在使用Atom编辑器和atom-typescript,在我的编辑器中没有得到任何错误/警告。但是当我在同一个目录下运行tsc时,我得到了上面的错误。我以为他们应该使用相同的tsconfig.json文件,但显然不是这样。

5jdjgkvh

5jdjgkvh1#

我想我找到了一个有用的东西:

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

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

biswetbf

biswetbf2#

还有另一种方法:如果你不希望生成的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; }
x6h2sr28

x6h2sr283#

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

const enum AnimalInfo {
Tiger = "Tiger",
Lion = "Lion"
}

let tigerStr = "Tiger";

if (tigerStr === AnimalInfo.Tiger) {
  console.log('true');
} else {
  console.log('false');
}
gywdnpxw

gywdnpxw4#

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

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

其中ProductTypes为export enum ProductTypes{Merchandises,Goods,...}

b0zn9rqh

b0zn9rqh5#

原始日期:2018年8月

在我的例子中,上述解决方案都不起作用,原因是我将枚举值转换为枚举对象。
在那之后,我试图知道枚举是否等价于另一个枚举对象...所以我创建了以下generic函数:

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;
    }
    if (typeof v !== validType) {
      v = enumType[v];
    }
    if (typeof v !== validType) {
      v = enumType[v];
    }
    return v || null;
  }

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

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无效时,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'
}
1dkrff03

1dkrff036#

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

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

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

uajslkp6

uajslkp67#

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

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

pqwbnv8z8#

在打印脚本中,示例枚举:

enum Example {
   type1,
   type2
};

被转换为javascript到这个对象中:

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

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

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';
8ulbf1ek

8ulbf1ek9#

抛出错误是因为编译器意识到该语句始终为false,因此是多余的。你声明了两个明显不相等的变量,然后试着看看它们是否相等。
如果您将其更改为例如:

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) {
  ...
}

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

相关问题