原文:dmitripavlutin.com/typescript-…
ts类型中,any可以被赋值为任意类型。
但很多ts导师并不鼓励使用any——使用any就放弃了类型限制,这违背了我们使用ts的初衷。
TS 3.0及以上版本提供了一种与any非常相似的特殊类型——unknown。你可以将一个类型多变的值指定为unknown类型。
那么问题来了:any和unknown的区别在哪儿呢?
1、unknown VS any
为了更好的理解两者的区别,我们来写一个函数,并且调用这个函数的唯一参数:
function invokeAnything(callback: any) {
callback();
}
invokeAnything(1);
因为参数callback 是任意类型的,所以代码 callback() 不会触发任何类型报错——当一个数据的类型定义为any,你可以给他赋任何值。
但是当你运行这些代码的时候,会引发以下报错:
1 is a number and cannot be invoked as a function
TypeScript没有提前提醒你来规避这个错误。
如何做到既允许函数invokeAnything可以接收任何类型的参数,又强制对参数进行类型检查呢?比如:如果参数是函数,则对其进行调用。
类型unknown像any一样,可以被赋值为任意类型,但是当你准备使用定义为unknown类型的数据时,TS会强制对类型进行校验。这正是我们需要的:
function invokeAnything(callback: unknown) {
callback(); // Object is of type 'unknown'.
}
invokeAnything(1);
由于入参callback的类型是unknown,代码 callback()会有类型错误:Object is of type 'unknown'。
显然,TypeScript在我们企图调用非函数的时候保护了我们。
你需要在使用类型为unknown的数据之前,先做类型检查。在上面的例子中,你可以在调用入参之前,先检查其是否是一个函数。
function invokeAnything(callback: unknown) {
if (typeof callback === 'function') { //类型检查
callback();
}
}
invokeAnything(1);
添加 typeof callback === 'function' 的检查之后,你就可以安全的调用callback了,unknown类型已经缩小为Function类型了。这下没有类型错误也没有运行错误了!
2、unknown 和 any 的思维模式
事实上,当我学习unknow的时候我难以理解这种类型的思维模式。
既然都是可以接受任意值的类型,它跟any到底有何不同呢?
下面两个规则帮助我理解了两者之间的区别:
- You can assign anything to unknown type but you have to do a type check or type asertion to operate on unknown.
你可以将任何类型的值给unknown,但是你使用的时候必须做类型检查或者类型断言。
- You can assign anything to any type and you can perform any operation on any.
你可以将任何类型的值给any以及你可以随意使用它
上面两个例子完全论证了unknown和any的异同。
3、结论
unknow和any是两个特殊类型,都可以接收任意值。
相对于any,我们更推荐unknown,因为unknown更安全: 你必须在使用之前进行类型断言或者缩小范围到具体一种类型。
挑战: can you write a utility type IsUnknown which evaluates to true if T is unknown and false otherwise?