还是严肃点吧,TypeScript越来越受到开发者们的青睐,但经常看到为了省事而写的 any 和 unknown 有什么区别呢?(划重点,面试常考喔!)今天就来用实际的例子来看看吧。
先说结论
| Type | 结论 |
|---|---|
any | 任何内容都可以被当作 any 类型,而且你可以对 any 类型做任何操作 |
unknown | 任何内容都可以被当作 unknown 类型,但在对 unknown 类型做操作/使用之前需要判断其更具体的类型 |
Talk is cheap, Show me the code
如果这段文字描述无法很好的解决你的疑惑,那么一起看看下边的例子吧。
示例1
let variable: any = undefined;
variable = 10;
variable = false;
let variable: unknown = undefined;
variable = 10;
variable = false;
以上两个代码块都可以成功通过TypeScript的类型检查,也印证了结论中的前半句,任何内容都可以被当作 any 或 unknown 类型。
示例2
let anyValue: any = 10;
let unknownValue: unknown = 10;
let number1: number = anyValue;
let number2: number = unknownValue; // Error, Type 'unknown' is not assignable to type 'number'.(2322)
可以发现将类型为 unknown 的值赋值给类型类型为 number 的变量时TS的类型检查就会报错了,这也印证了结论中关于unknown的后半句话,在对 unknown 类型做操作/使用之前需要判断其更具体的类型。
没问题,将上边的赋值语句稍作修改,成功通过了类型校验。
let number2: number = typeof unknownValue === "number" ? unknownValue : 0;
示例3
// Static Type Checking Phase - All Good!
const magicFunction = (param: any) => {
console.log(Math.round(param));
console.log(param.charAt(0));
console.log(param.push(1));
}
magicFunction(true);
// Runtime
// "Executed JavaScript Failed:" param.charAt is not a function
以上函数在代码编写也就是TypeScript做静态检查期间是不会报出任何错误的,可以看到函数中先后把param当作了数字、字符串、数组来进行操作。
而显然传入的布尔值是无法做这些操作的,对应的错误到了运行阶段才报了出来。
这印证了在声明了param为 any 类型后,TS默认可以对其 做任何操作
而当使用 unknown 替换掉 any 时
// ⚠ Static Type Checking Phase - Error!
const magicFunction = (param: unknown) => {
console.log(Math.round(param)); // Argument of type 'unknown' is not assignable to parameter of type 'number'.(2345)
console.log(param.charAt(0)); // Object is of type 'unknown'.(2571)
console.log(param.push(1)); // Object is of type 'unknown'.(2571)
}
如果未对param做类型断言,是无法通过TS的类型检查的,这也就是结论中的后半句 对 unknown 类型做操作/使用之前需要判断其更具体的类型
按照如下方法判断具体类型后,再对相应类型做合法的操作,就可以顺利通过类型校验了
// Static Type Checking Phase - All Good!
const magicFunction = (param: unknown) => {
if (typeof param === "number") {
console.log(Math.round(param))
} else if (typeof param === "string") {
console.log(param.charAt(0))
} else if (Array.isArray(param) && param.every(item => typeof item === "number")) {
console.log(param.push(1));
}
console.log("No valid type overlap");
}
magicFunction(true);
// Runtime
// 'No valid type overlap'
总结与思考
unknown和any都是 TypeScript 中的顶级类型,而unknown可以理解为更安全的any(如果要对unknown执行操作,必须使用类型断言或者缩小到特定的类型)- 如果可以的话请使用具体的类型声明,除非真的无法预知传入参数的类型(比如抽象出的公用函数)实在要使用也请优先使用
unknown - 不要让你的代码变成anyscript,让和你一起开发的伙伴多说 🐂🍺 而不是 “王德发”