相同点
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()
区别
1、any 类型的变量将会跳过类型检测,但是 unknown 不会
2、any 类型 可以赋值给任何类型,任何类型也可以赋值给 any 类型
3、unknown 类型 只能赋值给 unknown 和 any 类型,任何值都可以赋给unknown 类型
4、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
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
5、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
type Z1 = unknown & 1 // 1
type Z2 = unknown & '1' // '1'
type Z3 = unknown & {a:1} // {a:1}
type Z4 = unknown & unknown // unknown
type Z5 = unknown & null // null
type Z6 = unknown & undefined // undefined
type Z7 = unknown & any // any
type Z7 = null & undefined // never
两者不同的地方在于, 被赋予 any 类型的变量将会跳过类型检测,但是 unknown 不会
any 类型
我们可以简单的给一个定义:“I don’t care”,简单的说就是我不在意,因为any 类型
并不会经过 类型检查器,所以它毫不在意你给它的是什么类型,或者说它要用在什么地方
unknown 类型
我们也可以简单的给一个定义:“I don’t know”,简单的说就是我不知道,作为和 any 类型
一样的 Top Type
,我们可以给unknown 类型
赋值任何类型,但是你要是想要拿它来做一些事的时候,对不起,他都是不允许的,因为,它不知道啊,它不知道它能不能完成你交给它的任务,所以,它就会给出报错
any 类型 可以赋值给任何类型,任何类型也可以赋值给 any 类型
unknown 类型 只能赋值给 unknown 和 any 类型,任何值都可以赋给unknown 类型
打个比方:
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 的工具类型,就能够更简单的实现了。