【问题标题】:Possible to use enums to restrict values?可以使用枚举来限制值吗?
【发布时间】:2021-08-20 07:32:03
【问题描述】:

我们可以使用如下文字类型轻松限制支持的值

type GenderConfig = {
  gender: 1 | 0
}

const obj: GenderConfig = {
  gender: 100 // throw error because value is not 1 or 0
}

现在我想尽可能避免使用幻数1 & 0

所以我尝试为它定义一个枚举

enum Gender {
  MALE= 1,
  FEMALE=0,
}

type GenderConfig = {
  gender: Gender
}

const obj: GenderConfig = {
  gender: 100 // This doesn't throw error anymore?
}

Playground link

令人惊讶的是,gender: 100 不再抛出我不明白其背后原理的错误?

【问题讨论】:

  • 枚举几乎在所有语言中都有这个问题。这是因为 enum 在一天结束时只是一个命名数字。因此,如果您说某事是某种枚举,那并不会真正阻止您直接使用整数。或不同的整数。或解析为整数的表达式(在编译时不知道是哪一个)。 Java 使枚举成为一种适当的类型,因此它们不同的,而不是一些带有名称的整数。 TS 反而使枚举只是命名为数字字符串。
  • 当你希望它成为枚举的一部分时,你没有理由在性别中输入一个数字。正如@VLAZ 指出的那样,枚举仅用于命名数字的目的。因此,无论值是什么,枚举的使用都将分配一个数字。因此,如果您创建了一个新人,那么您可以写:gender: Gender.MALE 以使该人成为男人。无论您的代码如何处理男性(他们可能是或更改为多少)。因此枚举用于分配数字或保持它们一致 - 而不是像您的第一个示例中那样限制。
  • 如果您不需要能够在遗留代码中使用 0 和 1,您可以使枚​​举字符串值 enum Gender {MALE= "MALE",FEMALE="FEMALE"} 不那么好,但它会强制调用 const obj: GenderConfig = {gender: Gender.MALE } 可能不会适合你的情况,但我想我会提到它以防万一 \o/
  • @RasmusLauridsen:我理解你的观点,但我有点不同意。 TypeScript 的唯一目的是为 JS 提供类型安全特性,由于 enums 是它们带来的特性之一,所以我认为允许它执行类型检查是公平的

标签: javascript typescript enums


【解决方案1】:

您在这里创建的是一个数字枚举。生成的 JavaScript 如下所示:

var Gender;
(function (Gender) {
    Gender[Gender["MALE"] = 1] = "MALE";
    Gender[Gender["FEMALE"] = 0] = "FEMALE";
})(Gender || (Gender = {}));

在控制台中,该对象如下所示:

Object
  0: "FEMALE"
  1: "MALE"
  FEMALE: 0
  MALE: 1

在底层,枚举实际上只是一个带有属性的 JavaScript 对象。它具有您定义的命名属性, 并且它们被分配了一个数字,表示它们存在的枚举中的位置(FEMALE 为 0,MALE 为 1),但是 该对象还具有数字键,其字符串值表示命名常量。

因此,您可以将数字传递给需要枚举的函数。枚举本身既是一个数字,也是一个已定义的常量。

这似乎破坏了 TypeScript 的类型安全方面,因为您可以将任意数字传递给期望此枚举的函数。 不过,它之所以有用有两个原因:

  1. 当您收到数字数据(例如,来自某个服务的 JSON 有效负载)时,您可以将其转换为枚举。
  2. 由于枚举成员具有数值,因此您也可以将它们用作位标志(尽管您可以设置数值 对于每个枚举成员,正如您在此处所做的那样,这可能会或可能不会很好地工作)。

关于第 (1) 点:如果您声明一个没有数值的枚举,例如这个:

enum Gender {
  MALE = "Male",
  FEMALE = "Female"
}

那么你不能再这样做了:

const gender: Gender = "Male";

您必须进行显式转换:

const gender = "Male" as Gender;

【讨论】:

    【解决方案2】:
    const MALE = 1;
    const FEMALE = 0;
    
    type Gender = typeof MALE | typeof FEMALE;
    
    type GenderConfig = {
      gender: Gender
    }
    
    const obj: GenderConfig = {
      gender: 100 // This is now throwing error
    }
    

    Playground

    我没有使用enums,而是将其更改为type,并通过使用consttypeof的组合,我可以避免幻数并提高可读性和一致性,感谢其他人的解释

    【讨论】:

      【解决方案3】:

      我不再使用枚举,因为它们有点复杂。也许这是可能的,但你可以使用这样的字符串:

      type Gender = 'female' | 'male';
      type GenderConfig = {
        gender: Gender
      }
      

      当然,如果您在某个时候确实需要数字表示,则可能需要添加一些映射。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-06-29
        • 1970-01-01
        • 2013-05-18
        • 1970-01-01
        • 1970-01-01
        • 2018-11-03
        • 1970-01-01
        相关资源
        最近更新 更多