TypeScript中的any、unknown、never如何理解

本博客 hjy-xh,转载请申明出处

any

在TS中使用any类型,可以用来表示允许赋值给变量任意类型,这种方式与直接使用JS没有太大差别,无法享受到TS的类型检查,在可能出错的地方也不会发现错误。

any类型本质上是类型系统的一个逃逸舱,那我们在什么情况下会使用该类型呢?

  • 无法确定当前类型时
  • 逐步向TS迁移时

而在编写代码的过程中,明确知道类型的时候,有时为了偷懒,使用了any,这是一种不好的行为。

而以下种种原因,可能都会对我们是否使用any有影响:

  • 添加类型时,需要编写大量代码,而any工作量很少
  • 已经通过必要的运行时检查以防御性的方式编写了代码,以确保没有错误
  • 有些参数很难正确输入,但是any更容易
  • 不知道参数是什么
  • 类型增加了很多复杂性,有时any更简单

使用any还会造成类型污染的问题:即any类型的对象会导致后续的属性类型都会变成any

1
2
3
4
5
let obj: any = { 
name: 'Cola'
}

obj.name = 1;

unknown

在TS的3.0版本中,引入了unknown类型,它可以这样理解成:**unknown类型是any的类型安全版本。**

这意味着如果要在TS中使用unknown类型时,需要知道它所指的类型,也就自然地推导出使用该类型的变量前,需要对该变量的类型进行断言。

1
2
3
4
5
6
7
8
9
10
11
12
function func(value: unknown) {
// @ts-ignore: Object is of type 'unknown'.
value.toFixed(1);

// Type assertion:
(value as number).toFixed(1); // OK

// 缩小为更具体的类型范围,包括 typeof 运算符,instanceof 运算符和自定义类型保护函数
if (typeof value === 'number') {
value.toFixed(1);
}
}

unknown类型只能被赋值给any类型和unknown类型本身。

因为只有能够保存任意类型值的容器才能保存unknown 类型的值,所以这个限制很合理。毕竟我们不知道变量中存储了什么类型的值。

never

never类型表示的是那些永不存在的值的类型,never类型是任何类型的子类型,也可以赋值给任何类型。

然而,没有类型是never的子类型或可以赋值给never类型(除了never本身之外),never用于那些永不可发生的情况:

  • 一个从来不会有返回值的函数(如:如果函数内含有 while(true) {});
  • 一个总是会抛出错误的函数(如:function foo() { throw new Error('Not Implemented') },foo 的返回类型是 never);

与 void 的差异

void表示没有任何类型,never表示永远不存在的值的类型

异同

  • anyunknown是TS中所谓的顶级类型:当把类型看作是值的集合时,any 和 unknown 是包含所有值的集合
  • never类型是TS中的底层类型:空集

以下或许是最佳实践

  • 如果不是有意忽略类型检查,不使用any
  • 如果要用any,可以考虑用unknown代替(进行断言后使用)

参考