never
never
是一种永不存在的值类型,它是一种底部类型。never
类型通常不是主动声明的,而是在意外情况下产生的,属于异常场景下的类型。
由于 never
是底部类型,是所有类型的子类型,因此它的值可以赋给所有类型的变量(但没有任何意义)。示例代码如下。
let a: never;
let boolean1: boolean = a;
let number1: number = a;
let string1: string = a;
let function1: () => void = a;
let object1: { x: number } = a;
let array1: number[] = a;
由于 never
是一种永不存在的值类型,因此给 never
类型的变量赋任何值都会引起编译错误。示例代码如下。
let a: never;
//编译错误:不能将类型"number"分配给类型"never"。ts(2322)
a = 1;
//编译错误:不能将类型"string"分配给类型"never"。ts(2322)
a = "hello";
//编译错误:不能将类型"boolean"分配给类型"never"。ts(2322)
a = true;
//编译错误:不能将类型"number"分配给类型"never"。ts(2322)
a = [1, 2, 3];
//编译错误:不能将类型"() => void"分配给类型"never"。ts(2322)
a = function () { console.log("hello") };
//编译错误:不能将类型"string"分配给类型"never"。ts(2322)
a = { x: "aa", y: 1 }
never
类型通常是由代码中的错误引起的,不需要显式使用,它通常在以下情景下自动产生。
-
使用了错误的类型判断语句。例如,以下代码声明了一个
unknown
类型的变量,并指定其值为字符串 “hello world!”,但接下来的判断语句存在错误,需要该变量既为number
类型又为string
类型才能执行后续代码。由于这种类型是不存在的,因此该变量将被判定为never
类型,引起编译错误。const uncertain: unknown = 'Hello world!'; if (typeof uncertain === 'number' && typeof uncertain === 'string') { //编译错误:类型"never"上不存在属性"length"。ts(2339) console.log(uncertain.length); }
-
使用了错误的类型操作。例如,以下代码声明了类型别名
A
,将boolean
类型与string
类型进行了交叉,但是并不存在既为boolean
类型又为string
类型的值,因此类型A
将被判定为never
类型。type A = boolean & string; //编译错误:不能将类型"number"分配给类型"never"。ts(2322) let a: A = 1;
-
出现无法推断的类型。例如,以下代码声明了一个函数,它拥有一个
string
类型的参数a
,在函数体中首先进行了判断,当a
为string
时执行if
分支,否则执行else
分支,但else
编译器无法推断else
分支下的参数a
的类型,因此会将其判定为never
类型,引起编译错误。function test(a: string) { if (typeof a == "string") { console.log(a.length); } else { //编译错误:类型"never"上不存在属性"length"。ts(2339) console.log(a.length); } }