any和unknown是typescript中的两种顶级类型,所谓的顶级类型,可以被理解成通用父类型,也就是包含所有类型。
//any
let value: any;
value = true; // OK
value = 24; // OK
value = "Hello World"; // OK
value = []; // OK
value = {}; // OK
value = Math.random; // OK
value = null; // OK
value = undefined; // OK
value = new TypeError(); // OK
value = Symbol("type"); // OK
//unknown
let value: unknown;
value = true; // OK
value = 24; // OK
value = "Hello World"; // OK
value = []; // OK
value = {}; // OK
value = Math.random; // OK
value = null; // OK
value = undefined; // OK
value = new TypeError(); // OK
value = Symbol("type"); // OK
那么问题来了,既然any和unknown都可以表示任意类型,那它们的区别是什么。
-
任何类型都可以是any类型,any类型就相当于是免检标签,给了开发者很大的自由,typescript允许any类型的值进行任何操作,对它一路绿灯。
-
任何类型也都可以是unknown类型,但与any完全相反,unknown类型就像是typescript给打上了一个重点检查的标签。在没有对它进行类型检查之前,unknown类型的变量是不能进行任何操作的。
先看个例子:
function invokeCallback(callback: any) {
try {
callback();
} catch (err) {
console.error(err)
}
}
invokeCallback(1);
上面的代码,在编译期间不会提示任何错误,但在运行期间会抛出运行时错误,由此可看出,any类型给了开发者人员极大的自由度,但同时也带来了一些隐患。
为了解决 any 类型存在的安全隐患,TypeScript 团队在 3.0 版本时,引入了 unknown 类型,你可以把它理解成类型安全的 any 类型。
那么unknown类型的类型安全体现在哪里,我们先看接下来的例子
function invokeCallback(callback: unknown) {
try {
// Object is of type 'unknown'.(2571)
callback(); // Error
} catch (err) {
console.error(err)
}
}
invokeCallback(1);
相比 any 类型,TypeScript 会对 unknown 类型的变量执行类型检查,从而避免出现 callback 参数非函数类型。要解决上述问题,我们需要缩小 callback 参数的类型的范围,即可以通过 typeof 操作符来确保传入的 callback 参数是函数类型的对象:
function invokeCallback(callback: unknown) {
try {
if (typeof callback === 'function') {
callback();
}
} catch (err) {
console.error(err)
}
}
invokeCallback(1);
我们还可以使用instanceof或用户自定义类型等方式来减小类型的处理范围
declare function isFunction(x: unknown): x is Function;\
function f20(x: unknown) {
if (x instanceof Error) {
x; // Error
}
if (isFunction(x)) {
x; // Function
}
}
另外,需要注意的是,unknown 类型的变量只能赋值给 any 类型和 unknown 类型本身。
let value: unknown;
let value1: unknown = value; // OK
let value2: any = value; // OK
let value3: boolean = value; // Error
let value4: number = value; // Error
let value5: string = value; // Error
let value6: object = value; // Error
let value7: any[] = value; // Error
let value8: Function = value; // Error