【查漏补缺系列-ts篇】枚举、[any, unknown, void, never]

前言: 本类文章初衷只用作记录个人的学习博客,哪里有漏补哪里,不做任何其他商业用途。欢迎讨论,不喜勿喷。后面要是有遗漏的相关知识点,也会相应的补上。如果本篇文章能帮到你,我也会很愉快,共勉😁

目录

  1. 编译环境
  2. 枚举
  3. [any,unknown,void,never]
  4. 参考文献

编译环境

全局安装Typescript:

  • npm install typescript -g

全局安装ts的编译工具

  • npm install ts-node -g

枚举

枚举允许开发人员定义一组命名常量。使用枚举可以更轻松地记录意图,或创建一组不同的案例。TypeScript 提供基于数字和字符串的枚举。TS目前有数字和字符串两张枚举。

数字枚举

ts 复制代码
enum Direction {
  Js,
  Ts,
  Dart
}

console.log(Direction.Js, Direction.Ts, Direction.Dart) // 0 1 2

const respond = (message: Direction): void => {
  console.log('print:', message)
}

respond(Direction.Js) // 0

数字枚举初始化为0,并且以下的所有成员都会自动递增。

ts 复制代码
enum Direction {
  Js,
  Ts = 2,
  Dart
}

console.log(Direction.Js, Direction.Ts, Direction.Dart) // 0 2 3

可在任意成员更改其的默认下标,更改后会从当前位置以更新后的值作为初始值继续递增。

字符串枚举

ts 复制代码
enum Direction {
  Js = 'JavaScript',
  Ts = 'TypeScript',
  Dart = 'Dart'
}

console.log(Direction.Js, Direction.Ts, Direction.Dart) // JavaScript TypeScript Dart

字符串枚举其可读性和意图相较数字枚举更佳。

异构枚举

ts 复制代码
enum Direction {
  Js,
  Ts = 10 * 30,
  Dart = Js | Ts,
  Java = 5,
  Python = 'test',
  Go = 'test'.length
}

console.log(
Direction.Js, // 0
Direction.Ts, // 300
Direction.Dart, // 300 5 test 4
Direction.Java, // 5
Direction.Python, // test
Direction.Go) // 4

异构枚举其实就是在一个枚举中同时存在数字和字符串。不过正如官方所言,除非你真的想以巧妙的方式利用JavaScript的运行时行为,否则建议你不要这样做。

运行/编译时的枚举

ts 复制代码
enum Direction {
  Js,
  Ts,
  Dart
}

const callback = (obj: { Js: number }): number => {
  return obj.Js
} 

callback(Direction);

如上,枚举在运行时是一个真实存在的对象,所以它可以作为参数传递给函数。

ts 复制代码
enum Direction {
  Js = 'JavaScript',
  Ts = 'TypeScript',
  Dart = 'Dart'
}

// 相当于 type Prints = 'Js' | 'Ts' | 'Dart'
type Prints = keyof typeof Direction

const callback = (message: Prints): string => {
  return `to ${Direction[message]}`
} 

console.log(callback('Ts')) // to TypeScript

使用keyof typeof 获取enum的所有key。

反向映射

先声明一个普通的数字枚举

ts 复制代码
enum Direction {
  Js,
  Ts,
  Dart
}

通过key映射value

ts 复制代码
console.log(Direction['Dart']) // 2

也可以通过value映射key

ts 复制代码
console.log(Direction[0]) // Js

任意类型

any和unknown

any和unknown都可以被赋予任何类型的值,那它们有什么不一样呢? 先提结论:

  • any: 会绕过所有的ts验证
  • unknown:仅绕过赋值验证

any代表着任意,unknown代表着未知,看以下代码:

ts 复制代码
// 绕过类型验证和赋值验证
let a: any = 10

// 只绕过赋值验证
let b: unknown = 20

if (a >= 10) console.log(a) // 10

if (b >= 10) console.log(b) // 会报错,b类型为未知

我们发现,在赋值时,一切都是正常的。any和unknown都能被赋值为一个数字,但是将两个变量放入if中时,a正常执行了,而b会有报错,提示b的类型为未知。因为在判断时,编译器无法确定b的类型,故而报错。 由此可见,unknown在赋值方面和any一样,可以赋任意的值,但是它如果要进行类型验证时,则会无法通过。

ts 复制代码
if ((b as number) >= 10) console.log(b) // 20

通过类型断言,告诉编译器,我能确定b就是一个number类型,则正常通过。再看一个:

ts 复制代码
function invokeAnything(callback: any) {
  callback()
}

invokeAnything(1)

上面这段代码可以正常编译(哪怕callback传递的不是一个函数),因为callback被指定了any类型,会绕过ts的所有类型检测。我们改为unknown:

ts 复制代码
function invokeAnything(callback: unknown) {
 // 编译报错: callback类型为未知
  callback()
}

invokeAnything(1)

如果没告诉编译器callback的类型,在编译时就会报错。以下代码即可通过:

ts 复制代码
function invokeAnything(callback: unknown) {
  if (typeof callback === 'function') {
    callback()
  }
  
}

invokeAnything(1)

因此,最后的总结是:

  • 可以将任何内容分配给any类型,并且可以执行任何操作any。
  • 可以将任何内容分配给unknown类型,但必须进行类型断言或类型检查才能继续操作unknown。

void和never

void

void类型表示没有任何类型,声明一个void类型的变量基本没什么用,因为它只能被赋予undefined。更多是应用在一个函数没有返回值时,它的返回值类型就会是void。

ts 复制代码
let a: void = undefined

const fn = (message: string): void => {
  console.log(message)
}

never

never代表永远不会发生的类型,常用场景如:

  • 一个从来不会有返回值的函数。
  • 一个总是会抛出错误的函数。
ts 复制代码
const fn1 = (): never => {
  while(true) {}
}

const fn2 = (): never => {
  throw new Error('Network Error')
}

除了never,任何值都无法给never类型的变量赋值。

ts 复制代码
let a: never = 123 // Error: 不能将类型number的值分配给never

let foo: never = (() => { // ok,作为函数返回类型的never
  throw new Error('Error')
})()

void和never的区别

当一个函数返回空值时(哪怕没写return返回的也是undefined),它的返回值为void类型。但是,当一个函数永不返回时(或者总是抛出错误),它的返回值就为never。void类型可以被赋值undefined以及一个返回undefined的函数,而never除了本身,其他任何类型都不能赋值。

参考文献

dmitripavlutin.com/typescript-... jkchao.github.io/typescript-...

相关推荐
喵叔哟3 分钟前
重构代码之取消临时字段
java·前端·重构
还是大剑师兰特44 分钟前
D3的竞品有哪些,D3的优势,D3和echarts的对比
前端·javascript·echarts
王解44 分钟前
【深度解析】CSS工程化全攻略(1)
前端·css
一只小白菜~1 小时前
web浏览器环境下使用window.open()打开PDF文件不是预览,而是下载文件?
前端·javascript·pdf·windowopen预览pdf
方才coding1 小时前
1小时构建Vue3知识体系之vue的生命周期函数
前端·javascript·vue.js
阿征学IT1 小时前
vue过滤器初步使用
前端·javascript·vue.js
王哲晓1 小时前
第四十五章 Vue之Vuex模块化创建(module)
前端·javascript·vue.js
丶21361 小时前
【WEB】深入理解 CORS(跨域资源共享):原理、配置与常见问题
前端·架构·web
发现你走远了1 小时前
『VUE』25. 组件事件与v-model(详细图文注释)
前端·javascript·vue.js
Mr.咕咕1 小时前
Django 搭建数据管理web——商品管理
前端·python·django