一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第21天,点击查看活动详情。
前言
TypeScript 是对于 JavaScript 的超集,我们能通过 TypeScript 来发现编译时错误,以保证我们的代码是绝对安全的,而不是在运行时才来产生报错。
但是 TypeScript 提供了一个 any
类型,这个类型可以跳过 类型检查器 的检查,轻松的实现 AnyScript
在之后的版本当中,TypeScript 也发现了 any
的权利过于巨大,会产生很多的问题,“TS编译过不了怎么办,干any就完事了”,这种问题,所以在之后的版本,TypeScript 推出了 unknown
这个类型,那么 unknown
和 any
有什么不同的地方呢? 本文就稍微的聊一聊两者的区别所在。
本文就不聊两个类型都是什么了,这些网上介绍很多,主要来说说两个类型的共同的和不同点,以及,知道这些有什么用呢?
相同点
any
和 unknown
都是 Top Type
可以接收任何值作为他们的参数
比如:
let a: any = "asdasddsa" || 112 || {asds:2} || Symbol()
//...其他任何类型
let b: unknown = "asdasddsa" || 112 || {asds:2} || Symbol()
//...其他任何类型
就说明两个类型都是包容万物,就像是我们平时写 JavaScript 一样,一个变量你想要它在什么时候等于什么值都是可以的
let a: any = "asdasddsa" || 112 || {asds:2} || Symbol()
let b: unknown = "asdasddsa" || 112 || {asds:2} || Symbol()
a = Symbol()
b = Symbol()
区别
两者不同的地方在于, 被赋予 any
类型的变量将会跳过类型检测,但是 unknown
不会。
any
类型 我们可以简单的给一个定义:“I don't care”,简单的说就是我不在意,因为any
类型并不会经过 类型检查器,所以它毫不在意你给它的是什么类型,或者说它要用在什么地方。
unknown
类型 我们也可以简单的给一个定义:“I don't know”,简单的说就是我不知道,作为和 any
类型一样的 Top Type
,我们可以给unknown
类型赋值任何类型,但是你要是想要拿它来做一些事的时候,对不起,他都是不允许的,因为,它不知道啊,它不知道它能不能完成你交给它的任务,所以,它就会给出报错。
any
类型 可以赋值给任何类型,任何类型也可以赋值给 any
类型 因为它完全不在意。
但是 任何值都可以赋给unknown
类型,unknown
类型却不能赋值给 unknown
和 any
以外的任何类型,因为它不知道,它不知道它和你将要赋给的那个变量是不是安全的,打个比方:
let any1:any
let str:string = '2'
any1=str
str=any1
any
类型的随便赋值都是可以实现的,但是看unknown
类型
let str:string = '2'
let unknown1:unknown
unknown1=str
str=unknown1 //err:Type 'unknown' is not assignable to type 'string'.
编译就会给出报错,字符串不能够赋值一个unknown
类型的值,因为编译器它不知道你能不能赋值给字符串,所以给出了报错。
那么上面那段代码,要怎么才能够通过编译呢,很简单,它不知道它是什么类型,就要由程序员来告诉它:
let str:string = '2'
let unknown1:unknown
unknown1=str
if(typeof unknown1 == 'string'){
str=unknown1 //ok
}
我们可以使用类型守卫,或者是其他的任何方式,只要是你能够满足你要执行的代码的约束,比如说你要赋值给字符串,那你就一定也要是一个字符串,你要调用,那你就得是一个方法,以此类推。
这样做之后,虽然我们用了 Top Type
但是还是能够保证写出来的代码足够安全,起码不是产生那种,传一个字符串却拿来当方法调用这种情况。
体操一下
前面介绍了两种类型,那么来做一些简单的体操,第一个是,我们要怎么判断一个类型它是否是 any
类型。第二个,我们要怎么判断一个类型是否是 unknown
类型
IsAny
这里我们要用到一个 any
类型 的特性,那就是any
类型和任何类型的交集,都是any:
type Z1 = any & 1 // any
type Z2 = any & '1' // any
type Z3 = any & {a:1} // any
type Z4 = any & unknown // any
type Z5 = any & null // any
type Z6 = any & undefined // any
当然这是只有 any
才满足的一个特性,那么我们就可以利用这个特性来判断,一个数它是不是 any
type IsAny <T> = 0 extends 1&T ? true: false
type W1 = IsAny<undefined> // false
type W2 = IsAny<any> // true
只有当传入的 泛型 T 是 any
的时候,他才能够满足后面为 any
,这个条件类型的 0 或者 1 并不重要,重要的是,只有当 T 是 any
的时候,前后才能够满足,这样我们就能够判断一个类型是否是 any
。
IsUnknown
我最开始自己思考这个问题的时候,发现了 unknown
的一个特性,就是unknown
和任何类型的并集都是unknown
,除了 any
:
type Z1 = unknown | 1 // unknown
type Z2 = unknown | '1' // unknown
type Z3 = unknown | {a:1} // unknown
type Z4 = unknown | unknown // unknown
type Z5 = unknown | null // unknown
type Z6 = unknown | undefined // unknown
type Z7 = unknown | any // any
那么我们是不是可以按照上上面的思路,最后只要排除掉 any
就好了。
这里还有一个知识点,就是 keyof any
是 string | number | symbol
而 keyof unknown
是 never
我们可以以此来判断。
type IsUnknown <T> = 0 extends 1|T ?
keyof T extends never? true: false
: false
type e = IsUnknown<1>
后面发现我想的太麻烦了,我们之前说过 unknown
类型却不能赋值给 unknown
和 any
以外的任何类型,所以我们可以用这点来优化一下
type IsNotAny<T> = 0 extends 1 & T ? false : true ;
type IsUnknown<T> = unknown extends T ? IsNotAny<T> : false;
type Test1 = IsUnknown<any> // false
type Test2 = IsUnknown<unknown> // true
通过判断传入的类型是不是作为unknown
的父集,这样就能够把范围缩小到 unknown
和 any
,再通过上一个判断是否是 any
的工具类型,就能够更简单的实现了。
总结
今天简单的介绍了 any
和 unknown
类型,知道了它们之间的区别,所以在我们日常的开发当中,对一个变量的类型不确定的话,可以先尝试着用 unknown
类型,只有在实在是没办法的时候才使用 any
类型