TypeScript的枚举与类型约束

news/2024/4/28 23:13:56/文章来源:https://blog.csdn.net/sdasadasds/article/details/129709932

● 上一章我们讲了 TS 的接口

● 这一章, 我们就来聊一聊 TS 的枚举和约束

枚举

认识枚举

● 在很多计算机语言中都有枚举的概念, 但是 JS 中是没有枚举这个概念的, 为了弥补这个缺憾 在 TS 加入了枚举类型

● 什么是枚举呢 ?

枚举( mei ju ) : 枚举的意思就是一一列举, 把所有情况都列举出来, 那么取值的时候, 只有这几个可以使用, 其他的都不行

计算机语言里面的枚举( enumerations ) : 把所有的常量放在一个集合内, 让若干个常量变成一组有关联的内容

// 针对一个业务逻辑, 我需要频繁用到四个方向的字符串
const UP = 'up'
const RIGHT = 'right'
const DOWN = 'down'
const LEFT = 'left'

● 对于以上四个变量来说

● 我不管做任何逻辑, 我没办法限制你只能使用这四个变量中的一个

// 封装一个功能函数
function util(dir) {}

● 不管用什么方法, 你都没办法限制这个 dir 参数接收到的必须是上面列出的四个方向

● 这个时候, 我们就可以用到枚举了

● 首先, 在 TS 中, 利用 enum 关键字创建一个枚举集合, 把我们需要的四个常量放进去

enum Direction {UP = 'up',RIGHT = 'right',DOWN = 'down',LEFT = 'left'
}

● 制作了一个 DIrection 枚举集合, 那么就可以用这个集合来对某些数据进行限制了

function util(dir: Direction) {}

● 这就约定了, dir 这个参数的值只能是 Direction 这个枚举集合里面的常量, 其他都不行

● 只要你写的不是 Direction 这个枚举内的内容都不行

数字枚举

● 数字枚举 : 枚举类型中的每一个常量都是数字

● 在 TS 中, 枚举内的每一个常量, 当你不设置值的时候, 默认就是 number 类型

enum Pages {ONE,    // 0TWO,    // 1THREE   // 2
}

● 你在枚举内的常量, 第一个默认值是 0, 后面的依次 +1 递增

此时

Pages.ONE => 0

Pages.TWO => 1

Pages.THREE => 2

● 我们也可以自己指定值

enum Pages {ONE = 10,    // 10TWO = 20,    // 20THREE = 30   // 30
}

● 这个时候枚举集合内的常量就是我们指定好的值

● 我们也可以指定部分值

enum Pages {ONE = 10,    // 10TWO,         // 11THREE        // 12
}

● 指定常量后面的未指定常量, 就会按照 +1 的规则一次递增

enum Pages {ONE,         // 0TWO = 10,    // 10THREE        // 11
}
enum Pages {ONE,         // 0TWO = 10,    // 10THREE,       // 11FOUR = 30,   // 30FIVE         // 31
}

字符串枚举

● 字符串枚举 : 枚举集合中的每一个常量的值都是 string 类型

● 在 TS 内, 你必须要指定一个值, 才可能会出现 string 类型

enum Direction {UP = 'up',RIGHT = 'right',DOWN = 'down',LEFT = 'left'
}

● 在 TS 中, 枚举常量和任何内容都是不一样的, 包括原始字符串

function util(dir: Direction) {}

● 这是因为, 在 TS 中, 枚举内的每一个常量都是一个独一无二的值

● 所以当你用枚举去限定一个数据的时候, 用的时候也只能用枚举内的值

● 这样也避免你因为手误出现的单词错误, 比如你会不会认为 'form' 和 'from' 是一个单词呢

 

异构枚举

● 异构枚举 : 其实就是在一个枚举集合内同时混合了数字枚举和字符串枚举

● 但是你大概率是不会这样使用的, 因为我们作为一组数据的集合, 一般不会把数字和字符串混合在一起使用

enum Info {ONE,UP = 'up',TWO = 2,LEFT = 'left'
}

● 在这里有一个点需要注意

因为在枚举集合内, 当某一个 key 你没有设置值的时候, 会默认按照上一个的值 +1

所以如果前一个是 字符串枚举, 那么下一个必须要手动赋值, 不然会报错

如果前一个是 数字枚举, 那么下一个可以不必要手动赋值, 会按照上一个 +1 计算

枚举合并

● 在 TS 内的枚举, 是支持合并的

● 多个枚举类型可以分开书写, 会在编译的时候自动合并

enum Direction {UP = 'up',RIGHT = 'right',DOWN = 'down',LEFT = 'left'
}enum Direction {TOP = 'top',BOTTOM = 'bottom'
}function util(dir: Direction) {}util(Direction.BOTTOM)
util(Direction.LEFT)

● 这里定义的两个枚举都叫做 Direction, 会在编译的时候自动放在一起, 不会出现冲突

反向映射

● TS 内的数字枚举, 在编译的时候, 会同时将 key 和 value 分别颠倒编译一次

enum Pages {ONE,    // 0TWO,    // 1THREE   // 2
}

●  以这个为例, 他是如何进行编译的呢

var Pages;
(function (Pages) {Pages[Enum["ONE"] = 0] = "ONE"Pages[Enum["TWO"] = 1] = "TWO"Pages[Enum["THREE"] = 2] = "THREE"
})(Pages || (Pages = {}));

● 编译完毕的结果

Pages = {ONE: 0,TWO: 1,THREE: 2,'0': 'ONE','1': 'TWO','2': 'THREE'
}

● 也就是说, 我们在 TS 内使用的时候, 如果是数字枚举

● 那么我们可以通过 key 得到对应的数字, 也可以通过对应的数字得到对应的 key

enum Pages {ONE,    // 0TWO,    // 1THREE   // 2
}console.log(Pages.ONE)    // 0
console.log(Pages.TWO)    // 1
console.log(Pages.THREE)  // 2
console.log(Pages[0])     // 'ONE'
console.log(Pages[1])     // 'TWO'
console.log(Pages[2])     // 'THREE'

常量枚举

● 常量枚举, 是在枚举的基础上再加上 const 关键字来修饰

● 会在编译的时候, 把枚举内容删除, 只保留编译结果

● 并且对于数字枚举来说, 不在支持反向映射能力, 只能利用 key 来访问

● 非常量枚举

enum Pages {ONE,    // 0TWO,    // 1THREE   // 2
}console.log(Pages.ONE)
console.log(Pages.TWO)
console.log(Pages.THREE)

○ 编译完毕的 js 文件

● 常量枚举

const enum Pages {ONE,    // 0TWO,    // 1THREE   // 2
}console.log(Pages.ONE)
console.log(Pages.TWO)
console.log(Pages.THREE)

○ 编译完毕的 js 文件

类型约束

● 在 TS 中, 还有一个很神奇的关键字, 叫做 type

● type 又叫做类型别名有很多神奇的功能, 不仅能支持 interface 定义的对象结构, 还支持任何手写类型

● 先来看一个很简单的例子

let n1: number | string | boolean
let n2: number | string | boolean
let n3: number | string | boolean

● 观察上面一段代码, 我们定义了 n1 和 n2 和 n3 三个变量

○ 对于类型的限制都是 number 或者 string 或者 boolean

● 写起来的时候就非常麻烦

● 这个时候, 我们就可以使用 type 对其进行别名设置

type Info = number | string | boolean
let n1: Info
let n2: Info
let n3: Info

● 这样一来, 我们的代码是不是变得简洁了起来

● 可能小伙伴们认为这个用的并不多, 但是 type 也不是只有这一个功能

type 的常见使用

● 基本类型的别名

type n = number
let num: n = 100

○ 这是一个非常基础的使用, 把 number 这个类型起了一个别名叫做 n

○ 今后再用 n 来限制变量的时候, 其实就是在使用 number

●  基本类型联合

type i = number | string
let str: i = '千锋大前端'
str = 100

○ 这就是联合类型, 那 number 或者 string 这个类型齐了一个别名叫做 i

○ 我们再用 i 来限制变量的时候, 这个变量就被限制为了 number 或者 string

●  对象类型

type User = { name: string, age: number }
let person: User = { name: '千锋大前端', age: 10 }

○ 这就是对象类型, 和 interface 很像, 用处基本一致

● 对象联合类型

type User = { name: string, age: number }
type Person = User & { gender: boolean }
let person: Person = { name: '千锋大前端', age: 10, gender: true }

○ 这就是对象联合类型, 和 interface 的 extends 继承很像

● 元组类型

type data = [ number, string ]
let info: data = [ 10, '千锋大前端' ]

● 常量限定

type color = 'yellow' | 'orange' | 'blue'
function util(c: color) {}
util('yellow')

○ 这个 color 被限定为了几个值, 将来用 color 去约束一个变量的时候

○ 这个变量只能接受这几个值, 这里和 enum 比较像了

type 和 interface 的共同点

1.  都可以约束 对象 或者 函数 类型

○ interface

interface User { name: string; age: number }
interface Func { (x: number): number }

○ type

type User = { name: string; age: number }
type Func = (x: number) => number

○ 我们看到, 两个定义方式略有区别, 但是后期用法基本一致

2.  扩展类型

○ interface 使用 extends 进行继承

interface Person {name: stringage: number
}// 使用 extends 关键字继承自 Person
interface Student extends Person {classRoom: number
}
let s: Student = { name: '千锋大前端', age: 10, classRoom: 1 }

○ type 使用 交叉(&) 来实现

type Person = {name: stringage: number
}// 使用 交叉(&)
type Student = Person & {classRoom: number
}
let s: Student = { name: '千锋大前端', age: 10, classRoom: 1 }

3.  联合类型

○ interface 使用 extends 继承 type

type Person = {name: stringage: number
}// 使用 extends 关键字继承自 Person
interface Student extends Person {classRoom: number
}
let s: Student = { name: '千锋大前端', age: 10, classRoom: 1 }

○ type 使用 交叉(&) 扩展 interface

interface Person {name: stringage: number
}// 使用 交叉(&)
type Student = Person & {classRoom: number
}
let s: Student = { name: '千锋大前端', age: 10, classRoom: 1 }

type 和 interface 的区别

1.  interface 支持多次声明自动合并, type 不支持

interface User {name: stringage: number
}
interface User {classRoom: string
}
/*真实的 User 接口{name: stringage: numberclassRoom: string}
*/

○ type 如果声明重名标识符会报错

2.  对于 ES6 模块化语法的默认导出语法

○ interface 支持声明的同时进行默认导出

export default interface User {name: stringage: number
}

○ type 必须先声明, 在默认导出

type User = {name: stringage: number
}
export default User

○ 必须要先声明好, 在进行默认导出, 如果直接连写默认导出, 会报错

3.  type 可以使用 typeof 关键字去获取某一数据类型

let box = document.querySelector('.box')
type EleType = typeof box

○ 这里定义了一个 EleType 标识符, 会自动根据 typeof 关键字检测的 box 的类型限制

4.  type 支持使用 in 关键字去遍历成映射类型

type names = 'firstName' | 'lastName' | 'AKA'
type nameType = {[key in names]: string
}
/*真实的 nameType 类型{firstName: stringlastName: stringAKA: string}
*/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_274541.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PyTorch 深度学习实战 | 基于 ResNet 的花卉图片分类

“工欲善其事,必先利其器”。如果直接使用 Python 完成模型的构建、导出等工作,势必会耗费相当多的时间,而且大部分工作都是深度学习中共同拥有的部分,即重复工作。所以本案例为了快速实现效果,就直接使用将这些共有部…

【C++初阶】六、模板初阶(函数模板+类模板)

文章目录泛型编程函数模板函数模板的概念函数模板的格式函数模板的原理函数模板的实例化模板参数的匹配原则类模板类模板的定义格式类模板的实例化泛型编程 引入 - 通用的交换函数 如果让你编写一个函数,用于两个数的交换。在C语言中,我们会用如下方法…

我让Chat GPT准备了几份SAP 顾问英文面试自我介绍的模板,大家感受一下

有个朋友说有个面试要用英文来做自我介绍,我灵机一动,不如让Chat GPT准备了几份SAP 顾问英文面试自我介绍的模板,大家感受一下。我看下来感觉写的还是中规中矩,可以一用,。 模板1 Sure, I can help you with that! Her…

【Java学习笔记】39.Java 多线程编程

Java 多线程编程 Java 给多线程编程提供了内置的支持。 一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。 多线程是多任务的一种特别的形式,但多线程使用了更小的资源开销。 这里定义和…

navigator 拓宽前端视野

前言💐 写本文的起因是最近做了一个共享屏幕在线演示ppt的需求,发现了navigator的新大陆。原来web端开启屏幕共享是如此的简单,在接触之前还以为是多么高大上的功能,需求评审时内心还有些慌张。 人总是对自己不了解的东西心生恐惧&#x1f6…

VMware虚拟机卸载详细教程

安装过VMware虚拟机的小伙伴,90%可能都会遇到这样的问题:安装容易,卸载难。而且卸载不干净,就会导致后续安装和使用出现各种Bug。今天就给大家详细说说如何彻底干净的从本机卸载VMware。 1. 卸载之前,需要先关闭VMware…

【ChatGPT】Notion AI 从注册到体验:如何免费使用

欢迎关注【youcans的GPT学习笔记】原创作品,火热更新中 【ChatGPT】Notion AI 从注册到体验1. Notion AI 介绍1.1 Notion AI 简介1.2 Notion AI 的核心能力1.3 Notion AI 与 ChatGPT 的比较2. Notion AI 国内用户注册2.1 PC 端用户注册2.2 移动端用户注册3. Notion …

如何用C语言实现渣男通讯录

注意:纯属玩笑,博大家一乐,切勿当真📖首先我们要知道一个渣男通讯录有哪些信息要包含哪些功能1.你的通讯录要装多少个女朋友你得规定吧;2.每个女朋友的姓名,年龄,电话,爱好这些要有吧…

springboot项目中外卖用户下单业务功能之需求分析+数据模型+功能开发(详细步骤)

一、需求分析 移动端用户将菜品或者套餐加入到购物车后,可以点击购物车种的 去结算 按钮,页面跳转到订单确认页面,点击 去支付 按钮则完成下单操作。 二、数据模型 用户下单业务对应的数据表为orders表和order_detail表: order…

ESP32-CAM 环境搭建(离线)

云盘:Arduino IDE链接:https://pan.baidu.com/s/1yk_tKH8eK8okp5z9qv1TLg 提取码:pz2h内含:IDE arduino-ide_nightly-20230322_Windows_64bit.zipSDK esp32_package_2.0.5_arduinocn.exe步骤1,IDE为绿色版,…

57、C语言程序设计谭浩强第五章习题

1、输入两个正整数m和n,求其最大公约数和最小公倍数 辗转相除法&#xff1a; #include <stdio.h>int main(){int m,n,temp;scanf("%d %d",&m,&n);if(m<n){tempm;mn;ntemp;}int dn*m;int r;while(rm%n){mn;nr;}printf("最大公因数为:%d&#…

ONES 入选北大光华 MBA 整合实践项目,推动校企合作

近日&#xff0c;ONES 旗下开源问答社区软件 Answer 入选北京大学光华管理学院 MBA 整合实践项目&#xff0c;并受邀出席项目启动会。同时入选的还有国电投清洁能源基金、京东零售、瑞尔集团、美国丹纳赫集团、大众汽车&#xff08;中国&#xff09;和贝壳找房六家国内外知名企…

队列----数据结构

队列&#x1f506;队列的概念&#x1f506;队列的结构&#x1f506;队列的实现&#x1f506;设计循环队列&#x1f506;循环队列的结构&#x1f506;循环队列的实现&#x1f506;结语&#x1f506;队列的概念 队列&#xff1a;只允许在一端进行插入数据操作&#xff0c;在另一端…

5G、工业4.0、车载以太网……TSN时间敏感网络能给我们带来哪些市场机会?

TSN是一项面向未来的新兴技术&#xff0c;它定义了以太网数据传输的时间敏感机制&#xff0c;为标准以太网增加了确定性和可靠性&#xff0c;以确保数据实时、确定和可靠地传输。这些扩展使得以太网能够应用于更加广泛的行业中&#xff0c;进而带来了更多新的市场机会。 1. 5G…

电力行业等保定级评级依据是什么?分为几个等级?

最近看到不少电力行业小伙伴在问&#xff0c;电力行业等保定级评级依据是什么&#xff1f;分为几个等级&#xff1f;今天我们小编就来给大家简单回答一下&#xff0c;仅供参考哦&#xff01; 电力行业等保定级评级依据是什么&#xff1f;分为几个等级&#xff1f; 【回答】&a…

【2023.3.18 美团校招】

文章目录1. 小美剪彩带2. 最多修改两个字符&#xff0c;生成字典序最小的回文串1. 小美剪彩带 题意&#xff1a;找出区间内不超过k种数字子数组的最大长度 使用双指针的方式&#xff0c;用哈希表来统计每个数出现次数。在双指针移动的过程中&#xff0c;动态的维护区间内不同数…

bean的作用域和生命周期和后置处理器以及作用域对生命周期的影响~

scope属性可以指定bean的作用范围&#xff1a; 在spring中可以通过配置bean标签的scope属性来指定bean的作用域范围&#xff0c;各取值含义参照表如下&#xff1a; 编写spring_test.xml文件&#xff1a; <?xml version"1.0" encoding"UTF-8"?> &…

Spring Quartz项目实现Job的动态控制

一、简单介绍 Quartz可以对job进行简单控制&#xff0c;但不支持分布式&#xff0c;也没有管理界面和任务分片&#xff0c;但使用起来比较简易。 二、创建简单Demo 我们开始简单使用一下&#xff0c;首先创建Demo&#xff0c;在pom文件中加入以下依赖。 <parent><g…

golang项目实战2023/03/21

初始化项目首先建立一个文件夹在文件夹下面建一个main.go文件执行初始化命令行go mod init page // page 为自己的项目名称 go mod tidy 安装框架 go get gorm.io/gorm // gorm go get gorm.io/driver/mysql // 这里是用的sql数据库 go get -u github.com/gin-gonic/gin // 这…

Numpy 广播域

NumPy广播(Broadcast)&#xff0c;广播(Broadcast)是 numpy 对不同形状(shape)的数组进行数值计算的方式&#xff0c; 对数组的算术运算通常在相应的元素上进行。不同形状指的是&#xff0c;大小不同当然不是指的维度&#xff0c;但是要求数组各维度的长度相同例如&#xff1a;…