讲解

类型断言(type assertion)用 as 告诉编译器「这个值的类型我比你清楚,按我说的来」:value as string。断言不做任何运行时转换,只是把编译器的判断覆盖掉——所以它是责任的转移:从「编译器保证」变成「你保证」。合法断言的范围是两类型「有足够重叠」(一个能赋给另一个的某个方向);完全不沾边的类型之间断言会被拒绝,需要先 as unknown 再 as 目标类型——这个双重断言是明确的危险信号,出现时几乎总该停下来想想别的办法。

常见的正当场景:DOM 查询(getElementById 返回 HTMLElement | null,你知道它是 canvas)、JSON.parse 的结果(返回 any,你断言成接口——但记住运行时数据没有校验,断言只是假设)、收窄编译器跟不上的控制流。不正当的典型:为了消红而 as,把后端返回断言成理想形状然后崩在用户端。

satisfies 是 4.9 版本引入的「校验但不改写」操作符:expr satisfies T 检查 expr 是否满足 T,但表达式的类型保持推断出的精确类型不变。它完美解决了配置对象的两难——标注了类型就丢字面量精度,不标注又没校验。satisfies 两全:既检查形状,又保留 "light" 这样的字面量类型供后续精确使用。

示例

DOM 场景的断言(配合空值处理):

const root = document.getElementById("app") as HTMLDivElement | null;
if (root !== null) {
  root.dataset.ready = "true";
  console.log("容器已就绪:", root.tagName);
} else {
  console.log("没有 #app 容器(本示例在非 DOM 环境运行)");
}

JSON.parse 断言 + 运行时再兜底的稳妥写法:

interface Settings {
  theme: string;
  fontSize: number;
}

function parseSettings(raw: string): Settings {
  const data = JSON.parse(raw) as Partial<Settings>; // 先断言成「可能缺」
  return {
    theme: typeof data.theme === "string" ? data.theme : "light",
    fontSize: typeof data.fontSize === "number" ? data.fontSize : 14,
  };
}

console.log(parseSettings('{"theme":"dark"}'));
console.log(parseSettings("{}"));

satisfies:校验形状 + 保留精度:

type Palette = Record<string, { fg: string; bg: string }>;

const palettes = {
  light: { fg: "#000000", bg: "#ffffff" },
  dark: { fg: "#eeeeee", bg: "#111111" },
} satisfies Palette;

// 精确类型保留:键是 "light" | "dark",值的颜色是字面量
const mode = "dark" as keyof typeof palettes;
console.log(`${mode} 前景色:${palettes[mode].fg}`);

常见坑

  • as 链消红:as unknown as T 出现的地方,十有八九是类型设计错了,先检查上游类型。
  • 断言外部数据后不做校验:JSON.parse(...) as User 只是把炸弹往后传;关键数据加运行时校验(typeof 检查或 zod)。
  • const 断言与类型断言混淆:as const 是「保留字面量精度」,as T 是「覆盖判断」,两者名字相近、用途完全不同。
  • satisfies 当标注用:expr satisfies T 后变量类型仍是推断类型,不是 T;需要「类型就是 T」时用普通标注。

小结

as 转移责任,能不用就不用,用了要在附近留校验;as unknown as 是警报;satisfies 兼顾校验与精度。下一章讲让收窄更优雅的自定义类型守卫与断言函数。