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); } }