在 TypeScript 中有没有办法检查一个对象是否是枚举类型?

10
enum Direction {
    Up = 1,
    Down,
    Left,
    Right
}

if (typeof Direction === 'enum') {
    // doesn't work
}

有没有办法检查上面的代码是否确实是一个枚举


你为什么想要检查它是否为枚举?你所说的“检查”是指在运行时检查吗?但枚举是编译时构造。 - user663031
编译前检查。原因是我想将该对象转换为数组,想知道是否需要删除该对象的一半属性。我想知道在尝试进行转换之前,是否有非常干净的方法来判断对象是否属于这种类型的数据结构。 - jcroll
2个回答

6

枚举被编译成简单对象,具有双向映射:

name => value
value => name

因此,你示例中的枚举编译为:
var Direction;
(function (Direction) {
    Direction[Direction["Up"] = 1] = "Up";
    Direction[Direction["Down"] = 2] = "Down";
    Direction[Direction["Left"] = 3] = "Left";
    Direction[Direction["Right"] = 4] = "Right";
})(Direction || (Direction = {}));

所以Directiontypeof是一个普通的"object"。在运行时无法知道该对象是否为枚举类型,除非向该对象添加更多字段。

编辑

有时候你不需要尝试使用特定的方法来解决问题,你可以改变方法。
在这种情况下,你可以使用自己的对象:

interface Direction {
    Up: 1,
    Down: 2,
    Left: 3,
    Right: 4
}
const Direction = {
    Up: 1,
    Down: 2,
    Left: 3,
    Right: 4
} as Direction;

或者:

type Direction = { [name: string]: number };
const Direction = { ... } as Direction;

那么将这个对象转换成一个数组应该很简单。

没错。但是有没有一种方法可以在编译之前检测到呢?TypeScript 有没有可能检测到这样的事情? - jcroll
我会作弊,只保留整数键。 - jcroll
你可以像你建议的那样检查这个对称性,但也许在这种情况下你并不需要使用枚举。请检查我的修订答案。 - Nitzan Tomer
1
是的,我理解了那部分。但是,如果您将其用作枚举,则一开始就不需要进行区分,因为您的函数可以在不担心删除一半属性的情况下进行转换。 - Nitzan Tomer
是的,但是在那之上我使用了一个接口。 - Nitzan Tomer
显示剩余7条评论

3

就记录而言,以下是一种确定对象是否为枚举的方法:

  isEnum(instance: Object): boolean {
    let keys = Object.keys(instance);
    let values = [];

    for (let key of keys) {
      let value = instance[key];

      if (typeof value === 'number') {
        value = value.toString();
      }

      values.push(value);
    }

    for (let key of keys) {
      if (values.indexOf(key) < 0) {
        return false;
      }
    }

    return true;
  }

1
它在当前状态下接受null,但除此之外非常有用,谢谢! - ForestG
这是一个相当缓慢的操作,只是为了获取一个微不足道的类型。 - ATL_DEV
1
这对于字符串枚举无效,因为它们没有反向映射:https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-4.html#string-enums - 9me

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接