小红学Typescript: 一文让你彻底掌握枚举🧐

前言

通俗来说,枚举就是对一个对象的所有可能取到的值的集合, 在Typescript使用enum关键字来定义枚举。

应用场景

比如方向 有上下左右; 商品的交易状态 有等待买家付款、买家已付款、卖家已发货以及交易成功; 颜色 有红色、蓝色等; 有星期一、星期二....星期日; 有一月到12月等等表示有限数据集的都可以使用枚举。 比如方向 有上下左右; 商品的交易状态 有等待买家付款、买家已付款、卖家已发货以及交易成功; 颜色 有红色、蓝色等; 有星期一、星期二....星期日; 有一月到12月等等表示有限数据集的都可以使用枚举。

定义枚举

我们要使用一组相关的命名常量如星期的组合,这时候可以定义一个枚举类型:

ts 复制代码
// 定义一个枚举类型 Weekday,表示一周的工作日
enum Weekday {
    Monday,
    Tuesday,
    Wednesday,
    Thursday,
    Friday,
}

数字枚举

数字枚举的特点

数字枚举的特点:枚举变量所对应的值是自动递增的。

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

使用:

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

    ts 复制代码
    enum Weekday {
        Monday = 10,
        Tuesday,
       	...
    }

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

使用枚举

使用枚举也很简单,像对象一样,枚举名.枚举成员。

ts 复制代码
let today: Weekday = Weekday.Wednesday;
console.log(today); // 输出: 2,因为 Wednesday 在枚举中的索引是 2

每一个枚举成员都可以当作枚举本身进行使用

ts 复制代码
function getWeekDay(day: Weekday) {
	console.log(day)
}
getWeekDay(Weekday.Friday) // 4

枚举成员使用计算值

通过上面的例子我们可以发现,每个枚举成员都有一个与之关联的值,该值可以是常量(如我们Weekday枚举类型中的Monday成员就是常量值),但也可以是计算值。计算值是的意思就是枚举的值是被计算出来的。

ts 复制代码
function getNum() {
	return 10
}
enum Weekday {
	Monday = getNum(),
	Tuesday,
	Wednesday,
	Thursday,
	Friday
}

此时Monday的值就是计算值, 但是上面的代码报错 了,这是因为没有初始化的枚举要么需要放在第一个,要么必须位于使用数字常量或其他常量枚举成员初始化的数字枚举 之后。这里的"其他常量枚举成员初始化的数字枚举"可能有点拗口,其实就是这样:

ts 复制代码
enum Num {
	one = 1,
	two = 2
}
enum Weekday {
	Monday = Num.two,
	Tuesday,
	Wednesday,
	Thursday,
	Friday
}

这里的Monday的值就是其他常量枚举成员初始化的数字枚举值。

字符串枚举

字符串枚举是啥

枚举不仅可以用数字常量初始化,也可以用字符串常量初始化,当一个枚举中成员的值都是字符串,那么这个枚举就是字符串枚举了。

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

  • 与数字枚举相比, 字符串枚举没有"递增"这个概念了。
ts 复制代码
enum Weekday {
	Monday = "Monday",
	Tuesday = "Tuesday",
	Wednesday = "Wednesday",
	Thursday = "Thursday",
	Friday = "Friday"
}

其他

其他的使用与数字枚举一样。

异构枚举

异构枚举是啥

如果枚举成员的值是数字常量和字符串常量混合的枚举类型,那么这个枚举就是异构枚举了 。

ts 复制代码
enum Weekday {
	Monday = '星期一',
	Tuesday = '星期二',
	Wednesday = '星期三',
	Thursday = 1,
	Friday = 2
}

这样做看起来很怪异,但或许在某些特殊的场合下会用到, 使用场景极少。

常量枚举值

枚举的值可以是常量也可以是计算值。 常量枚举值指的是在编译期间就可以取到值,计算值则需要在运行期间才能取到值。

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

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

计算枚举值

除了上述三种情况,其他的所有情况都属于计算值, 计算值需要返回一个number

ts 复制代码
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才能运行,那么枚举编译后的结果是什么呢?

数字枚举的编译

ts 复制代码
enum Weekday {
	Monday,
	Tuesday,
	Wednesday,
	Thursday,
	Friday
}

经过编译后是下面的结果

ts 复制代码
"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 = {}));

从上面的编译结果来看,我们不仅能使用Weekday.Monday得到枚举值0, 还能通过Weekday[Weekday.Monday]得到字符串"Monday"这个键名。这也是枚举的反向映射

字符串枚举的编译

ts 复制代码
enum Weekday {
	Monday = "Mon",
	Tuesday = "Tues",
	Wednesday = "Wednes",
	Thursday = "Thurs",
	Friday = "Fri"
}

经过编译后是下面的结果

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

从上面的编译结果来看,我们可以通过Weekday.Friday来获取枚举值Fri, 但是我们不能用 Weekday[Weekday.Friday]来获取到字符串Friday , 这是因为具有字符串值的枚举成员不会生成反向映射

const 枚举

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

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

ts 复制代码
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)

编译后的结果

ts 复制代码
"use strict";
function foo(params) {
	if (4 /* Weekday.Friday */ === params) {
		return 'Friday';
	}
	else {
		return 'not Friday';
	}
}

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

枚举Weekday没有产生额外的对象或函数,使用枚举成员的地方直接编译成了对应的值。

获取枚举键和值的类型

在开发自定义组件的时候,很多组件都会支持颜色属性,我们通常会定义这样的枚举类型。

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

但是为了更好的体验,可以允许用户传递进来如red这样的字符串,这个时候我们可以让我们定义的枚举类型的枚举成员的keyvalue都组装成联合类型。

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

扩展

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

源码中定义了ShapeFlags枚举类型描述了vnode的类型。

ts 复制代码
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进行权限操作。

vnode授权

如上面代码所示COMPONENT = ShapeFlags.STATEFUL_COMPONENT | ShapeFlags.FUNCTIONAL_COMPONENT

此时代表COMPONENT被授予了ShapeFlags.STATEFUL_COMPONENT | ShapeFlags.FUNCTIONAL_COMPONENT权限。

vnode鉴权

如果我们要判断一个vnode是否有COMPONENT权限,只需要COMPONENT & VnodeType 只要为0就代表没有权限。

ts 复制代码
const hasPer = ShapeFlags.COMPONENT & ShapeFlags.ELEMENT

console.log(hasPer) // 0

hasPer为0表示没有权限

ts 复制代码
const hasPer = ShapeFlags.COMPONENT & ShapeFlags.FUNCTIONAL_COMPONENT

console.log(hasPer) // 2

hasPer不为0表示有权限。

总结

相信通过此文你已经掌握枚举了。

相关推荐
Myli_ing几秒前
考研倒计时-配色+1
前端·javascript·考研
余道各努力,千里自同风3 分钟前
前端 vue 如何区分开发环境
前端·javascript·vue.js
软件小伟12 分钟前
Vue3+element-plus 实现中英文切换(Vue-i18n组件的使用)
前端·javascript·vue.js
醉の虾34 分钟前
Vue3 使用v-for 渲染列表数据后更新
前端·javascript·vue.js
张小小大智慧42 分钟前
TypeScript 的发展与基本语法
前端·javascript·typescript
hummhumm1 小时前
第 22 章 - Go语言 测试与基准测试
java·大数据·开发语言·前端·python·golang·log4j
asleep7011 小时前
第8章利用CSS制作导航菜单
前端·css
hummhumm1 小时前
第 28 章 - Go语言 Web 开发入门
java·开发语言·前端·python·sql·golang·前端框架
幼儿园的小霸王2 小时前
通过socket设置版本更新提示
前端·vue.js·webpack·typescript·前端框架·anti-design-vue
疯狂的沙粒2 小时前
对 TypeScript 中高级类型的理解?应该在哪些方面可以更好的使用!
前端·javascript·typescript