# 类型断言
类型断言(Type Assertion)可以用来手动指定一个值的类型。
# 语法
值 as 类型;
或
<类型>值;
在 tsx 语法(React 的 jsx 语法的 ts 版)中必须使用前者,即 值 as 类型
# 用途
类型断言的常见用途有以下几种
# 将一个联合类型断言为其中一个类型
之前提到过,只能访问此联合类型的所有类型中共有的属性或方法,于是我们可以事先假定一个值的是其中一个类型
interface Cat {
name: string;
run(): void;
}
interface Fish {
name: string;
swim(): void;
}
function isFish(animal: Cat | Fish) {
if (typeof (animal as Fish).swim === "function") {
return true;
}
return false;
}
# 将一个父类断言为更加具体的子类
当类之间有继承关系时,类型断言也是很常见的,比如下面这个错误类:
class APIError extends Error {
code: number = 0;
}
class HTTPError extends Error {
statusCode: number = 200;
}
function isAPIError(error: Error) {
if (typeof (error as APIError).code === "number") {
return true;
}
return false;
}
这里我们通过其 code 属性是否为 number 类型来判断是否为一个 API 错误,但是其父类 Error 并没有 code 属性,因此在做判断时,我们需要先假定该类是一个APIError
。
# 将任何一个类型断言为 any
理想情况下,TypeScript 的类型系统运转良好,每个值的类型都具体而精确。但有的时候我们确实需要临时进行调整,此时我们可以断言一个类型为 any。
将一个变量断言为 any 可以说是解决 TypeScript 中类型问题的最后一个手段。切记不要滥用。
# 将 any 断言为一个具体的类型
在日常的开发中,我们不可避免的需要处理 any 类型的变量,它们可能是由于第三方库未能定义好自己的类型,也有可能是历史遗留的或其他人编写的烂代码,还可能是受到 TypeScript 类型系统的限制而无法精确定义类型的场景。
遇到 any 类型的变量时,我们可以选择无视它,任由它滋生更多的 any。
我们也可以选择改进它,通过类型断言及时的把 any 断言为精确的类型,亡羊补牢,使我们的代码向着高可维护性的目标发展。
举例来说,历史遗留的代码中有个 getCacheData,它的返回值是 any
function getCacheData(key: string): any {
return (window as any).cache[key];
}
interface Cat {
name: string;
run(): void;
}
const tom = getCacheData("tom") as Cat;
tom.run();
上面的例子中,我们调用完 getCacheData 之后,立即将它断言为 Cat 类型。
这样的话明确了 tom 的类型,后续对 tom 的访问时就有了代码补全,提高了代码的可维护性。
# 兼容
从上面的例子中,我们可以总结出:
- 联合类型可以被断言为其中一个类型
- 父类可以被断言为子类
- 任何类型都可以被断言为 any
- any 可以被断言为任何类型
兼容: 断言后的类型属于断言前类型的子集
TIP
要使得 A 能够被断言为 B,只需要 A 兼容 B 或 B 兼容 A 即可