# 「Typescript之旅」: 带你轻松掌握枚举🧐

701 阅读7分钟

## 定义枚举

``````// 定义一个枚举类型 Weekday，表示一周的工作日
enum Weekday {
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
}
``````

## 数字枚举

### 数字枚举的特点

• 我们没有初始化枚举类型的值的情况下，`Monday`的值是0、`Tuesday`的值是1、`Wednesday`的值是2， 而递增到`Friday`的值是4。

• 如果我们对枚举进行初始化

``````enum Weekday {
Monday = 10,
Tuesday,
...
}
``````

`Monday`被初始化为10， 因为枚举递增的特性，`Tuesday`的值是11， `Wednesday`的值是12，递增到`Friday`的值是14。初始化的值也可以是负数。

### 使用枚举

``````let today: Weekday = Weekday.Wednesday;
console.log(today); // 输出: 2，因为 Wednesday 在枚举中的索引是 2
``````

``````function getWeekDay(day: Weekday) {
console.log(day)
}
getWeekDay(Weekday.Friday) // 4
``````

### 枚举成员使用计算值

``````function getNum() {
return 10
}
enum Weekday {
Monday = getNum(),
Tuesday,
Wednesday,
Thursday,
Friday
}
``````

``````enum Num {
one = 1,
two = 2
}
enum Weekday {
Monday = Num.two,
Tuesday,
Wednesday,
Thursday,
Friday
}
``````

## 字符串枚举

### 字符串枚举与数字枚举的区别

• 与数字枚举相比， 字符串枚举没有“递增”这个概念了。
``````enum Weekday {
Monday = "Monday",
Tuesday = "Tuesday",
Wednesday = "Wednesday",
Thursday = "Thursday",
Friday = "Friday"
}
``````

## 异构枚举

### 异构枚举是啥

``````enum Weekday {
Monday = '星期一',
Tuesday = '星期二',
Wednesday = '星期三',
Thursday = 1,
Friday = 2
}
``````

## 常量枚举值

Typescript对什么才是常量枚举值有如下的定义：

1. 常量文字或者常量字符串
2. 对已定义的常量枚举成员的引用
3. 对常量枚举值进行`+`, `-`, `*`, `/`, `~` `%`, `<<`, `>>`, `>>>`, `&`, `|`,`^`算的也是属于常量枚举值

### 计算枚举值

``````enum ConstantComputedMember {
A = 1, // constant
B, // constant
C = 'abc', // constant
D = 1 + 1, // constant
F = 'a' + 'b', // constant
G = 1 << 2, // constant
H = A | B, // constant
I = A & B, // constant
J = [1, 2, 3].length, // computed
K = getNum() // computed
}
``````

## 枚举的编译结果

ts代码最终被编译成js才能运行，那么枚举编译后的结果是什么呢？

### 数字枚举的编译

``````enum Weekday {
Monday,
Tuesday,
Wednesday,
Thursday,
Friday
}
``````

``````"use strict";
var Weekday;
(function (Weekday) {
Weekday[Weekday["Monday"] = 0] = "Monday";
Weekday[Weekday["Tuesday"] = 1] = "Tuesday";
Weekday[Weekday["Wednesday"] = 2] = "Wednesday";
Weekday[Weekday["Thursday"] = 3] = "Thursday";
Weekday[Weekday["Friday"] = 4] = "Friday";
})(Weekday || (Weekday = {}));
``````

### 字符串枚举的编译

``````enum Weekday {
Monday = "Mon",
Tuesday = "Tues",
Wednesday = "Wednes",
Thursday = "Thurs",
Friday = "Fri"
}
``````

``````"use strict";
var Weekday;
(function (Weekday) {
Weekday["Monday"] = "Mon";
Weekday["Tuesday"] = "Tues";
Weekday["Wednesday"] = "Wednes";
Weekday["Thursday"] = "Thurs";
Weekday["Friday"] = "Fri";
})(Weekday || (Weekday = {}));
``````

## const 枚举

• typescript会将常规枚举编译成一个对象与一个自执行的匿名函数，但是创建对象与执行函数需要一定额外的成本， 有没有一种办法枚举只执行枚举的工作，而不产生额外的数据，于是Typescript新增了const 枚举。

• const 枚举的定义很简单，在常规枚举的定义`enum`前面加上 `const` 关键字即可。`const` 枚举只能用常量枚举，不能有计算值的枚举成员，而且`const` 枚举在编译期间完全被删除！

``````const enum Weekday {
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
}

function foo(params: number) {
if (Weekday.Friday === params) {
return 'Friday'
} else {
return 'not Friday'
}
}
foo(Weekday.Friday)
``````

``````"use strict";
function foo(params) {
if (4 /* Weekday.Friday */ === params) {
return 'Friday';
}
else {
return 'not Friday';
}
}

foo(4 /* Weekday.Friday */);
``````

## 获取枚举键和值的类型

``````enum Color {
Red = '#ff0000',
Green = '#00ff00',
Blue = '#0000ff'
}
function changeTheme(color: Color) {
this.color = color
}
``````

``````type KeyTypeColor = Lowercase<keyof typeof Color>
function changeTheme(color: Color | KeyTypeColor) { // color: Color | "red" | "green" | "blue"
this.theme = color
}
changeTheme('red')
``````

## 扩展

vue3源码中通过枚举加位运算符进行组合权限认证。

``````export const enum ShapeFlags {
ELEMENT = 1, // 普通的HTML元素
FUNCTIONAL_COMPONENT = 1 << 1, // 函数式组件
STATEFUL_COMPONENT = 1 << 2, // 有状态组件
TEXT_CHILDREN = 1 << 3, // 文本子节点
ARRAY_CHILDREN = 1 << 4, // 数组子节点
SLOTS_CHILDREN = 1 << 5, // 插槽子节点
TELEPORT = 1 << 6, // teleport组件
SUSPENSE = 1 << 7, // suspense组件
COMPONENT_SHOULD_KEEP_ALIVE = 1 << 8, // 需要被keep-live的有状态组件
COMPONENT_KEPT_ALIVE = 1 << 9, // 已经被keep-live的有状态组件
COMPONENT = ShapeFlags.STATEFUL_COMPONENT | ShapeFlags.FUNCTIONAL_COMPONENT
// 组件，有状态组件和函数式组件的统称
}
``````

### vnode鉴权

``````const hasPer = ShapeFlags.COMPONENT & ShapeFlags.ELEMENT

console.log(hasPer) // 0
``````

hasPer为0表示没有权限

``````const hasPer = ShapeFlags.COMPONENT & ShapeFlags.FUNCTIONAL_COMPONENT

console.log(hasPer) // 2
``````

hasPer不为0表示有权限。