“我正在参加「码上掘金挑战赛」详情请看:码上掘金挑战赛来了!”
“我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第4篇文章,点击查看活动详情”
扩展类型
基础类型已经适用于绝大数场景,但是扩展类型可以持续优化我们的代码,使得我们效率更高
具体分为:
- 类型别名
- 枚举
- 接口
- 类
枚举
定义
枚举通常约束某个变量,某个函数返回值等的取值范围.
其实字面量和联合类型配合使用, 也可以达到同样的目的, 这样的话要枚举做啥呢??
字面量类型的问题
①在类型约束位置,会产生重复代码。可以使用类型别名解决这个问题
let gender: '男' | '女';
gender = "女"
// 这个时候重复定义,产生重复代码
function searchGender(g: '男' | '女') {}
---
// 利用类型别名解决重复
type Gender = '男' | '女';
let gender: Gender
gender = "女"
function searchGender(g: Gender) {}
②定义的联合类型的数值。和使用真实的值不一样时,会产生大量的修改
// 项目经理要求改变类型,觉得男|女太俗了
type Gender = '李易峰' | '美女';
let gender: Gender
// 这个时候如果代码有几千行都赋值原来的定义,那要累死个人
gender = "女"
gender = "男"
function searchGender(g: Gender) {}
③字面量类型不会进入编译结果
// 编译成js后消失, 并且无法在ts中拿到所有定义的值去渲染或循环啥的
type Gender = '李易峰' | '美女';
如果项目中遇到后两个问题,那只能靠枚举大哥来解决啦
枚举的使用
- 使用格式
enum 枚举名 {
枚举字段1 = 枚举值1,
枚举字段2 = 枚举值2
}
解决第二个问题
enum Gender {
male = '李易峰',
female = '美女'
}
// 保持不变
let gender: Gender
gender = Gender.female
gender = Gender.male
console.log(Gender.female); // 美女
// 保持不变
function searchGender(g: Gender) {}
- 解决第三个问题,枚举会出现在编译结果中,编译结果中表现为对象
/**
* 这块内容相当于转化为一个对象
* {
* male: "\u674E\u6613\u5CF0",
* female: "\u7F8E\u5973"
* }
*/
var Gender;
(function (Gender) {
// 中文被转化为unicode
Gender["male"] = "\u674E\u6613\u5CF0";
Gender["female"] = "\u7F8E\u5973";
})(Gender || (Gender = {}));
let gender;
gender = Gender.female;
gender = Gender.male;
console.log(Gender.female);
function searchGender(g) { }
并且我们可以在ts代码里直接打印枚举, 就把他认为是一个对象就完事了
function print () {
const vals = Object.values(Gender)
vals.forEach(v=>console.log(v)) // 李易峰 美女
}
所以我们在做取值范围的时候,用枚举准没错
枚举细节玩法
- 枚举的字段值可以是字符串或数字
enum Gender {
male = [], // 报错: “含字符串值成员的枚举中不允许使用计算值。”
female = '美女'
}
- 数字枚举的值会自动递增, 每个增加1。 如果第一位不写,默认从0开始递增
enum level {
level1= 1,
level2,
level3,
}
console.log(level2) //2
console.log(level3) //3
---
enum level {
level1,
level2,
level3,
}
console.log(level1) //0
console.log(level2) //1
console.log(level3) //2
- 被数字枚举约束的变量,可以直接赋值为数字,
这会导致一系列的问题,最好不要这么做
enum level {
level1= 1,
level2,
level3,
}
let a:level = 2
数字枚举的编译结果 和字符串的枚举编译结果有差异
数字枚举便编译结果
var level;
(function (level) {
level[level["level1"] = 1] = "level1";
level[level["level2"] = 2] = "level2";
level[level["level3"] = 3] = "level3";
})(level || (level = {}));
ts源码
enum level {
level1= 1,
level2,
level3,
}
console.log(level)
{
'1': 'level1',
'2': 'level2',
'3': 'level3',
level1: 1,
level2: 2,
level3: 3
}
枚举的最佳实践
尽量不要在枚举中即出现字符串,又出现数字,这个会引发很多问题的出现- 使用枚举值,
尽量都使用枚举的字段名
枚举的扩展-位运算
什么是位运算?
是把两个数字换算成二进制后对每一位进行运算
包含这3种形式:
- 或运算: 对每一位去
||, 比较两者有一个为1就为1, 否者为0
let a = 1 | 8 //=>9, => 1001
// 推理过程如下:
0001
1000
1(0||1) 0(0||0) 0(0||0) 1(1||0)
- 且运算: 对每一位去
&&, 比较两者都为1才为1, 否者为0
let a = 1 & 8 //=>0, => 0000
// 推理过程如下:
0001
1000
1(0&&1) 0(0&&0) 0(0&&0) 1(1&&0)
- 异或运算: 对每一位去比较
异同, 如果相同=0,若果不同=1
let a = 1 ^ 8 //=>9, => 1001
// 推理过程如下:
0001
1000
1(不同) 0(相同) 0(相同) 1(不同)
枚举中使用位运算
位枚举,也称枚举的位运算, 主要是针对数字类型的枚举
我们如何理解呢, 举个例子:
现在有个需求: 需要完成读,写,创建,删除,四种权限的组合, 我们如何取用枚举实现呢?
- 第一步-
创建枚举
// 创建一个0-3的数字枚举, 包含读,写,创建,删除
enum Permission {
Read,
Write,
Create,
Delete
}
- 第二步-
设置值
// 利用2进制数值,去表示组合
enum Permission {
Read = 1, //=> 2^0, => 0001
Write = 2, //=> 2^1, => 0010
Create = 4, //=> 2^2, => 0100
Delete = 8 //=> 2^3, => 1000
}
- 第三步-
组合使用
利用或运算,组合设置权限:
// 设置可读,可写
// 注意这里是赋值, 不是定义类型
// 定义为数字枚举, 可以赋值任意数字
let p: Permission = Permission.Read | Permission.Write
let p: Permission = Permission.Read | Permission..Write | Permission.Delete
利用且运算,判断是否包含某个权限:
let p: Permission = Permission.Read | Permission.Write
function hasPermission(target: Permission, per: Permission) {
return (target & per) === per
}
// 判断p有木有可写权限
hasPermission(p, Permission.Write) // => true
利用且运算,删除某个权限:
let p: Permission = Permission.Read | Permission.Write
p = p ^ Permission.Write //=> p=1
hasPermission(p, Permission.Write) // => false