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类型内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!