any
概述
any
不必赘述,TypeScript 的逃逸仓,只要任何数据被转变成了 any
,开发者对该数据做任何操作都不会有报错提示。
使用场景
- 任何你想偷懒的场景
void
概述
大部分时候你可以视作 undefined
,或者当你关闭 strictNullChecks
时也可以视作 null
。
除此之外,void
与 undefined
还有一个关键的不同,那就是类型兼容性,void
在作为函数返回类型的时候可以兼容所有返回类型
使用场景
- 理论上其实所有使用
undefined
的地方都可以使用void
,TypeScript 并不会因此为难你。 - 但实际上推荐的用法是仅使用在 函数返回类型 的类型定义上,其他地方使用
void
多少会有歧义。
never
概述
如果说 void
从语义上可以理解为 空值,那 never
就可以视为在空值这一方面更进一步,表示压根就永远不会出现没有意义的变量。
笔者为了方便理解,喜欢用 “死值” 来表示 never
,虽然专业的计算机术语中没有这种表述方式。
比如说一个对象定义了这样两个键值
interface ExampleObj {
voidValue?: void
neverValue?: never
}
voidValue
尚且可以赋值 undefined
,而 neverValue
这个 “死值” 不可以赋值更不可以读取变量。
某种意义上来说对对象的键值设置 never
,就意味着你不希望该对象中出现这个键值。
还有几个更生动形象的例子来解释“死值”这一称呼的妙处,比如函数抛出错误或者内部会死循环。
// 正常函数不论是否显式的 return 值,默认都会返回 undefined
// 但如果函数直接中途抛出错误,那就意味着根本不会走到返回这一步,也就是说不存在返回值这一说
// 这个时候 never 就可以表示根本不存在返回值
function willThrowError(): never {
throw new Error('error')
}
// 死循环也同理
function infiniteLoop(): never {
for(;;){
// do something
}
}
使用场景
- 不希望对象上出现某个键值
- 函数不会走到返回这一步时,返回值可以设置为
never
unknow
概述
先抛出一个问题,对于外部来源的数据我们该怎么进行数据定义呢?
如果数据类型是 已知且稳定 的情况,我们可以选择对其专门写一个数据类型并使用类型断言即可,亦或者直接使用 any
偷懒。
但如果数据类型是 不稳定 的情况,或者由于数据来源是不可信的,从而导致数据类型是不确定的情况,数据类型该怎么办呢,这个时候 unknown
就出现了。
先说官方概念:
Anything is assignable to
unknown
, butunknown
isn’t assignable to anything but itself andany
without a type assertion or a control flow based narrowing. ——New ‘unknown’ top type
- 翻译一下:任何值都可以赋值给
unknown
,但是unknown
不能赋值给任何类型,除非赋值给自身或者进行了数据断言或者数据推断使之类型更加明确。 - 概括一下:
unknown
可以存储任何类型的值,但是使用的时候,需要直接或间接明确其数据类型才能使用。 - 核心意义:可以存储任何类型的值,但使用的时候不能随便使用。
一看核心意义是不是就发现,unknown
非常适合成为那些不确定的外部数据的类型,正如 unknown
这个单词的本意,并且如果你要使用 unknown
类型的数据要不直接断言成一种数据类型,要不就用逻辑代码判断其数据类型,收束其数据类型。而这一要求,不仅符合 TypeScript 的要求,也符合工程的严谨性。因为理论上外部数据都可以说是不稳定的,所以将所有外部数据都定义成 unknown
是最好的,只不过要使用它们的话会十分麻烦。
应用场景
- 使用 未知的 或者 不稳定的 数据来源的数据
其他
void 和 never 的区别
void
是“空值”,never
是“死值”
any 和 unknown 的区别
any
可以存储任何类型的值也可以赋值给任何类型的变量,虽然使用方便,但是通常会忽略一些隐性 bug。unknown
可以存储任何类型的值但不能赋值给其他任何类型的变量,虽然使用麻烦,但是 TypeScript 约束你的同时会让你的代码更安全。