
原文地址: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 进行操作前必须类型校验或缩小到特定的类型。

