如何在打字稿中检查类型是否为枚举

时间:2020-09-05 12:17:00

标签: typescript oop enums

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

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.

如何做到?

4 个答案:

答案 0 :(得分:1)

Javascript没有枚举的概念,因此不可能。在编译时,typescript将枚举定义转换为您日常使用的普通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 = {}));

答案 1 :(得分:1)

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


无论如何,似乎您对enum的运行时行为感兴趣,而不一定对它们的类​​型系统行为感兴趣,因此在接下来的内容中,我将担心在运行时而不是在编译器中回答您的问题。在运行时,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

答案 2 :(得分:0)

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

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

答案 3 :(得分:0)

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

我们可以先创建一个User-Defined Type Guard,如下所示:

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

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

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