TypeScript中的never类型你了解吗

 更新时间:2023年10月17日 10:40:37   作者:前端小码哥  
TypeScript 中的 never 类型,表示:永远不会发生的值的类型,换句话说,就是不可能存在的类型,即没有值的类型,那么你了解TypeScript中的never类型吗,感兴趣的朋友跟着小编一起来看看吧

1. never 类型的理解

TypeScript 中的 never 类型,表示:永远不会发生的值的类型。

换句话说,就是不可能存在的类型,即没有值的类型。

2. 可能会出现 never 类型的一些情况

2.1. 函数抛出异常

如果一个函数抛出异常,那么它的返回类型就是 never。因为在函数抛出异常后,会直接中断程序的运行,这使得程序不会继续执行到函数的返回语句那一步。

上面的例子中,函数 throwError 抛出异常,鼠标移到 throwError 函数上面,可以看到函数的返回值类型为 never。

2.2. 不会有返回值的函数

如果一个循环永远无法正常结束,比如无限循环或者总是抛出异常,那么该循环的类型被推断为 never。

上面的例子中,函数 infiniteLoop 是一个无限循环函数,没有任何的终止循环的语句,函数执行永远不会结束,因此不会有任何的返回值,鼠标移到 infiniteLoop 函数上面,可以看到函数的返回值类型为 never。

2.3. 类型判断或类型缩小的细化(全面性检查)

在条件语句中,如果 TypeScript 能够推断出某个分支永远不会执行,那么该分支的类型会被推断为 never 。

type Value = number | string;
const processValue = (value: Value) => {
  if (typeof value === "number") {
    // 在这个分支中,value 的类型被细化为 number
  } else if (typeof value === "string") {
    // 在这个分支中,value 的类型被细化为 string
  } else {
    // 在这个分支中,value 的类型被细化为 never,因为 value 不可能同时为 string 和 number
    const n: never = value
  }
}

上面的例子中,else 分支里面,value 的类型将被细化为 never 类型,然后我们将 value 赋值给一个显示声明了 never 类型的变量,如果逻辑正确,上面的代码可以正常编译通过,但如果你把 Value 的类型改成 number | string | boolean 的联合类型,此时 else 分支的 value 类型就会被细化成 boolean 类型,此时把 value 赋值给一个显示声明了 never 类型的变量就会报错。

type Value = number | string | boolean;
const processValue = (value: Value) => {
  if (typeof value === "number") {
    // 在这个分支中,value 的类型被细化为 number
  } else if (typeof value === "string") {
    // 在这个分支中,value 的类型被细化为 string
  } else {
    // 在这个分支中,value 的类型被细化为 boolean 类型,因为 value 不可能同时为 string 和 number
    // 此时,把 value 赋值给一个显示声明了 never 类型的变量 n 就会报错。
    // 下面的赋值语句会报错:不能将类型“boolean”分配给类型“never”。
    const n: never = value
  }
}

3. never 类型的特点

3.1. never 类型会从联合类型中移除

任意类型和 never 类型的联合类型都是其本身,就好比如:任意数字和0相加,都等于该数字。

type T1 = number | never;  // number
type T2 = string | never;  // string
type T3 = boolean | never; // boolean
type T4 = any | never;     // any
type T5 = unknown | never; // unknown
type T6 = never | never;   // never
type T7 = "abc" | never;   // "abc"
type T8 = 123 | never;     // 123

利用这个特点,我们可以做很多事情,比如:筛选。

我们可以利用条件类型把不符合类型 Type 的类型先转换成 never 类型,然后利用联合类型把 never 类型过滤掉,得到我们想要的结果。

type Filter<T, U> = T extends U ? T : never
type RESULT = Filter<"Echo" | 26 | true | "GuangZhou", string>

上面的代码,按照分布式条件类型机制,Filter<"Echo" | 26 | true | "GuangZhou", string> 将被分解成如下代码:

type RESULT = 
  | ("Echo" extends string ? "Echo" : never) 
  | (26 extends string ? 26 : never) 
  | (true extends string ? true : never) 
  | ("GuangZhou" extends string ? "GuangZhou" : never)

进一步被解析,得到如下代码:

type RESULT = "Echo" | never | never | "GuangZhou"

再一步解析,得到结果:

type RESULT = "Echo" | "GuangZhou"

3.2. never 类型与任意类型的交叉类型都是 never

type T1 = number & never;  // never
type T2 = string & never;  // never
type T3 = boolean & never; // never
type T4 = any & never;     // never
type T5 = unknown & never; // never
type T6 = never & never;   // never
type T7 = "abc" & never;   // never
type T8 = 123 & never;     // never

3.3. never 可以赋值给任意类型

由于 never 类型是所有其他类型的子类型,所以可以将 never 赋值给任何其他类型。

let n: never
let str: string = n
let num: number = n
let b: boolean = n
let any: any = n
let unknown: unknown = n
let func: () => void = n
let symbol: symbol = n
let n1: never = n

3.4. 其他类型不能赋值给 never

由于 never 没有子类型,所以除了 never 本身,任何类型都不能赋值给 never 类型。

let n: never
n = "Echo"               // 报错:不能将类型“string”分配给类型“never”
n = 26                   // 报错:不能将类型“number”分配给类型“never”
n = true                 // 报错:不能将类型“boolean”分配给类型“never”
n = [1, 2, 3]            // 报错:不能将类型“number[]”分配给类型“never”
n = Symbol()             // 报错:不能将类型“symbol”分配给类型“never”
n = {}                   // 报错:不能将类型“{}”分配给类型“never”
n = new Array()          // 报错:不能将类型“any[]”分配给类型“never”
n = (...arg: any) => {}  // 报错:不能将类型“(...arg: any) => void”分配给类型“never”

4. 总结

以上就是我对 TypeScript 中 never 类型的理解,如果有不正确的地方,欢迎大家在评论区多多指正!

到此这篇关于TypeScript中的never类型你了解吗的文章就介绍到这了,更多相关TypeScript never类型内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 使用JavaScript修改浏览器URL地址栏的实现代码

    使用JavaScript修改浏览器URL地址栏的实现代码

    这篇文章主要介绍了如何使用JavaScript修改浏览器URL地址栏,需要的朋友可以参考下
    2013-10-10
  • 使用BootStrap实现悬浮窗口的效果

    使用BootStrap实现悬浮窗口的效果

    本文给大家分享使用BootStrap实现悬浮窗口的效果,神奇的 bootstrap就自带了这个功能。所以就用bootstrap的popover插件做了,效果还不错,感兴趣的朋友参考下吧
    2016-12-12
  • js中的两种定时器区别是什么以及怎么清除定时器详解

    js中的两种定时器区别是什么以及怎么清除定时器详解

    在做项目中难免会碰到需要实时刷新,动画依次出现等等需求,这时候就需要定时器登上我们的代码舞台了,这篇文章主要介绍了js中两种定时器区别是什么以及怎么清除定时器的相关资料,需要的朋友可以参考下
    2026-01-01
  • JavaScript清空数组元素的两种方法简单比较

    JavaScript清空数组元素的两种方法简单比较

    这篇文章主要介绍了JavaScript清空数组元素的两种方法简单比较,罗列了几种常见的情况javascript数组的方法,并且比较了其中的两种常见方法,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-07-07
  • 最全正则表达式总结:验证QQ号、手机号、Email、中文、邮编、身份证、IP地址等

    最全正则表达式总结:验证QQ号、手机号、Email、中文、邮编、身份证、IP地址等

    这篇文章主要介绍了最全正则表达式:验证QQ号、手机号、Email、中文、邮编、身份证、IP地址等,通过语法介绍作用表达式等详细解释了正则表达式的使用,具体操作步骤大家可查看下文的详细讲解,感兴趣的小伙伴们可以参考一下。
    2017-08-08
  • 微信小程序wx.navigateTo方法里的events参数使用详情及场景

    微信小程序wx.navigateTo方法里的events参数使用详情及场景

    这篇文章主要介绍了微信小程序wx.navigateTo方法里的events参数使用详情及场景,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-01-01
  • javascript特殊日历控件分享

    javascript特殊日历控件分享

    这篇文章主要为大家详细介绍了javascript特殊日历控件的使用方法,展示了javascript日历控件实现效果,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-03-03
  • JavaScript模块导入和导出方式举例

    JavaScript模块导入和导出方式举例

    文章介绍了ES6模块化方法,涵盖命名导出(多值导出,需指定名称)、默认导出(单一值导出,简化使用)、动态导入(按需加载)及as关键字(重命名,解决冲突)等核心内容,对js模块导入和导出相关知识感兴趣的朋友一起看看吧
    2025-09-09
  • js日历功能对象

    js日历功能对象

    问题产生需求:做OA时弄到 备忘这个功能,想以日历的形式展现
    2012-01-01
  • JS Ajax请求如何防止重复提交

    JS Ajax请求如何防止重复提交

    这篇文章主要介绍了JS Ajax请求如何防止重复提交的相关资料,通过覆盖掉$.ajax而达到防止重复提交的问题,实现代码简单,需要的朋友可以参考下
    2016-06-06

最新评论