# 类型断言

类型断言(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 即可