原文地址:https://dmitripavlutin.com/typescript-unknown-vs-any/
any
类型的变量可以被赋值任何值:
let myVar:any = 0;
myVar = '1';
myVar = false;
许多 TypeScript 指南不建议使用 any
,因为它会丢掉类型限制 — 这恰是为何使用 TypeScript 的原因!
TypeScript (3.0+ 以上版本)还提供了一个特殊的类型 unknown
,类似于 any
。你同样也可以向 unkonwn
类型的变量赋值任何值:
TypeScript 3.0 introduces a new top type unknown. unknown is the type-safe counterpart of any. Anything is assignable to unknown, but unknown isn’t assignable to anything but itself and any without a type assertion or a control flow based narrowing. Likewise, no operations are permitted on an unknown without first asserting or narrowing to a more specific type.
let myVar:unknown = 0;
myVar = '1';
myVar = false;
现在的最大问题是:any
和 unknown
的区别是什么?
让我们在这篇文章中找到:
1. unknown vs any
为了更好的理解 unknown
与 any
的区别,让我们写一个函数以及内部调用它的唯一参数。
我们使 invokeAnything()
的参数为 any
类型:
function invokeAnything(callback: any) {
callback();
}
invokeAnything(1);
因为 callback
是 any
类型,callback()
语句不会触发类型错误,你可以对 any
类型的变量做任何事。
但是运行时脚本会抛出一个运行时错误:TypeError: callback is not a function
。1
是一个数字不能被当做函数调用 — 同时 TypeScript 没有保护你免受此种错误的影响!
如何允许 invokeAnythings()
函数接受任意类型的参数,但是强制对参数进行类型校验,例如:如果以函数来调用它?
欢迎 unknown
!
unknown
类型的变量与 any
类型的类似,接受任意值。但是当尝试使用 unknown
的变量时,TypeScript 强制一个类型校验。以此确保正是你所需的。
我们来把 callback
参数的类型从 any
改为 unknown
,然后看看发生了什么:
function invokeAnything(callback: unknown) {
callback();
Object is of type 'unknown'.
}
invokeAnything(1);
因为 callback
参数是 unknown
类型,callback()
语句有一个类型错误 Object is of type 'unknown'
。现在,与 any
相反,当调用时 TypeScript 使你免受参数非函数类型的错误。
在使用 unknown
类型的变量之前,你需要进行类型校验。在这个例子中,你需要简单的校验 callback
是否为函数类型:
function invokeAnything(callback: unknown) {
if (typeof callback === 'function') {
callback();
(parameter) callback: Function
}
}
invokeAnything(1);
已经添加了 typeof callback === 'function'
校验,你可以安全的调用 callback()
因为 unknown
已经缩小为 Function
类型。没有类型错误和运行时错误!非常棒!
2. unknown 与 any 的心智模型
说实在的,当我开始学习 unknown
时,理解起来确实困难。由于它与 any
都可以接收任何值,那到底有什么区别呢?
下面是帮助我理解它们不同的准则:
- 你可以给
unknown
类型的变量赋值任何值,但是对它进行操作之前必须类型检查或类型断言。 - 你可以把
unknown
想象为type unknown : number | string | boolean | ...
。 - 你可以给
any
类型的变量赋值任何值,以及给对它进行任何操作。
上面的代码已经很明白的演示了 unknown
与 any
之间的异同。
unknown
的例子:
function invokeAnything(callback: unknown) {
if (typeof callback === 'function') {
callback();
}
}
invokeAnything(1);
这里的类型检查是 typeof callback === 'function'
— 检测 callback
是否为一个函数。callback
的类型被限制为函数类型。
any
的例子:
function invokeAnything(callback: any) {
callback();
}
invokeAnything(1);
callback
是 any
类型,TypeScript 不会对 callback()
进行任何类型检查。
3. 总结
unknown
与 any
是两个特殊的可以接受任何值的类型。
因为 unknown
提供了类型安全,所以相比于 any
更推荐它 — 若你想对 unknown
进行操作前必须类型校验或缩小到特定的类型。