# 原始类型-void never

本节聚焦 TypeScript 扩充的原始类型

# void

void 在 JS 中实际是一个操作符,作用是运行后续表达式并返回 undefined,详细使用参见 MDN void (opens new window)。

TypeScript 利用 void 表示缺省值的情况,多用于注释没有返回值的函数,使用场景如下:

在变量上使用 void,会导致变量只能赋值为 undefined

// 定义一个函数,限制输入参数必须为 number 且返回值为 number
function add(a: number, b: number): number {
  return a + b;
}

// 合法
add(1, 2);

// 报错,缺少参数
add(1);

// 报错,返回值为 number 类型不能赋值给 string 类型的变量
let str: string = add(1, 2);

# never

never 表示类型的值不会发生的情况,多用于注解特殊的函数。

// 1. 该函数用于抛出错误,无法正常返回所以类型为 never
function error(msg: string): never {
  //该函会报错, 由于注解为 never 不允许在函数返回
  return 1;
  throw new Error(msg);
}

// 2. 函数有死循环,注解为 never
function calculate(): never {
  while (true) {
    // ...
  }
}

由于 never 的特殊性,不要作为变量类型来注解

let neverVal: never;

never = null; // 报错
never = undefined; // 报错
never = 1; // 报错

// 报错,注意理解此示例,虽然函数的返回类型为 never ,但是函数本声也是一个类型所以无法赋值给 never
neverVal = (): never => {
  throw new Error('demo');
};

// 此处合法,由于函数返回类型为 never ,通过触发函数执行达到赋值效果
neverVal = ((): never => {
  throw new Error('demo');
})();

阅读 The never type (opens new window) 进一步理解

# unknown 和 any

unknown 是 TypeScript 3.0 (opens new window) 提供的新的顶层类型,它是为了避免 any 这样没有任何类型校验逻辑而产生的安全类型。

unknown 类型的变量可以被赋予任何值,但是无法对其操作并赋值给其他非 any,unknown 的类型




















 







// any 类型可以被赋予任何值
let anyVal: any = 1;
anyVal = 'demo'; // 合法
anyVal = null; // 合法
anyVal = []; // 合法
anyVal + 1; // 合法
anyVal.a.v(); // 合法, 虽然没有任何属性 TypeScript 不会检查报错
let bar: string = anyVal; // 合法 TypeScript 检查变量为 any 类型所以兼容 string
let bar1: number = anyVal; // 合法
let bar2: null = anyVal; // 合法
let bar3: undefined = anyVal; // 合法

// unknown 类型也可赋予任何值,但是限制了赋值和操作,避免了 any 类型没有检查的错误
let unknownVal: unknown = 1;
unknownVal = 'demo'; // 合法
unknownVal = null; // 合法
unknownVal = []; // 合法
unknownVal + 1; // 报错, 由于不确定类型无法进行 + 运算
unknownVal.a.v(); // 报错, 不确定类型,所以无法调用此方法
unknownVal.toString(16); // 报错,虽然 unknown 的值为 1,但由于该类型为不确定类型所以操作报错
let bar11: string = unknownVal; // 报错,不确定类型不能复制给确定的类型
let bar12: number = unknownVal; // 报错
let bar13: null = unknownVal; // 报错
let bar14: undefined = unknownVal; // 报错
let bar15: any = unknownVal; // 合法, any 类型接受任何类型
let bar16: unknown = unknownVal; // 合法,因为是相同类型赋值

注意高亮的那行 unknownVal.toString(16) 虽然 unknownVal 的值为 1,但是由于 unknown 类型,限制对该变量执行 toString 方法。 你可以重温 值和类型章节,加深对 TypeScript 类型系统的核心是限制变量值的范围及操作来避免弱类型导致的问题! 这句话的理解!

进一步理解 unknown 的资料

# 类型断言(Type assertions)

类型断言 是 TypeScript 提供的显示告知编译器变量类型的语法。利用类型断言显示申明 unknownVal 变量为 number 类型,可以避免 unknownVal.toString(16) 的报错。

let unknownVal1: unknown = 1;

// 采用 <类型> 标注 unknownVal1 为 number 类型
(<number>unknownVal1).toString(16);
// 也可采用 as 语法,注意在 jsx 中只能采用此语法,因为尖括号表示标签!
(unknownVal1 as number).toString(16);

// 报错,类型断言只是显示告知 TypeScript 如何处理变量类型,并不会实际转换变量类型
unknownVal1.toString(16);

注意示例中的括号是为了确保断言的优先级为 unknownVal1 而非 unknownVal1.toString(16) 的返回值。

此外类型断言只对当前语句有效,它并不会改变变量的实际类型。不要和强制类型转换的语法混淆。

# 总结

本小节我们学习了几个特殊类型,其中 any,never 并不属于原始类型,而是平级于原始类型的顶层类型,为了方便讨论放在此处一并讲解。知识点如下:

  • 原始类型
    • void 用于无返回值的函数
    • never 用于无法产生返回值的函数例如抛出错误,死循环等
  • unknown 避免了 any 没有类型限制的错误
  • 类型断言 显示告知编译器变量类型,有两种书写格式
    • <类型> 变量或表达式前采用
    • as jsx 只能采用此语法