阅读 11

TS中unknown和any的区别

原文: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?

文章分类
前端
文章标签