可以使用枚举来限制值吗?

Possible to use enums to restrict values?

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

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 不再抛出错误,我不明白这背后的原理?

我不再经常使用枚举了,因为它们有点复杂。也许这在某种程度上是可能的,但您可以改用这样的字符串:

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

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

您在这里创建的是一个数字枚举。生成的 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;
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 的组合,我可以避免幻数并提高可读性和一致性,感谢其他人的解释