你了解TypeScript中的never类型吗?

1. never 类型的理解

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

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

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

2.1. 函数抛出异常

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

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

2.2. 不会有返回值的函数

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

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

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

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

typescript 复制代码
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 类型的变量就会报错。

typescript 复制代码
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相加,都等于该数字。

typescript 复制代码
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 类型过滤掉,得到我们想要的结果。

typescript 复制代码
type Filter<T, U> = T extends U ? T : never

type RESULT = Filter<"Echo" | 26 | true | "GuangZhou", string>

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

typescript 复制代码
type RESULT = 
  | ("Echo" extends string ? "Echo" : never) 
  | (26 extends string ? 26 : never) 
  | (true extends string ? true : never) 
  | ("GuangZhou" extends string ? "GuangZhou" : never)

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

typescript 复制代码
type RESULT = "Echo" | never | never | "GuangZhou"

再一步解析,得到结果:

typescript 复制代码
type RESULT = "Echo" | "GuangZhou"

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

typescript 复制代码
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 赋值给任何其他类型。

typescript 复制代码
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 类型。

typescript 复制代码
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 类型的理解,如果有不正确的地方,欢迎大家在评论区多多指正!

看完记得点个赞哦~ 谢谢!🤞🤞🤞

相关推荐
格子软件13 分钟前
2026年GEO优化系统源码级状态机与多模型调度拆解
java·前端·vue.js·人工智能·vue·geo
HUMHSX1 小时前
Vue 项目启动全流程解析:从入口文件到全局指令注册与页面渲染
前端·javascript·vue.js
有颜有货1 小时前
PMC生产排产的4种算法,一次讲清
java·服务器·前端
小虎牙0071 小时前
Android kotlin图片库Coil源码详解
android·前端
随风一样自由1 小时前
【前端领域】前端开发核心应用场景与落地实践
前端·前端框架
an317422 小时前
弹窗数据流设计的两种高阶架构实践
前端·vue.js·架构
谢尔登2 小时前
【React】 状态管理方案
前端·react.js·前端框架
用户2136610035722 小时前
Vue商品详情与放大镜组件
前端·javascript
半个落月2 小时前
从Tapas小Demo理清localStorage、事件与this
前端·javascript
李明卫杭州2 小时前
Vue2 中 v-model 处理不同数据结构的技巧
前端·javascript·vue.js