0Pricing
TypeScript Academy · 课时

断言与类型守卫

在可能的情况下,优先使用运行时检查,而不是断言。

断言与类型守卫 是 CoddyKit 上的免费 TypeScript Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 TypeScript Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 TypeScript Academy 课程共包含 4 节课。

让编译器相信的两种方式

当编译器不知道某个值的确切类型时,您有两种选择:对它进行断言(声明其类型),或对它进行守卫(在运行时证明其类型)。两者看起来相似,但安全性却大不相同。

function viaAssert(v: unknown): number {
  return (v as number) + 1; // claim
}
function viaGuard(v: unknown): number {
  return typeof v === 'number' ? v + 1 : 0; // prove
}
console.log(viaAssert(5), viaGuard(5), viaGuard('x'));

断言不会验证

断言是一种没有强制检查的承诺。如果您判断错误,错误就会漏到运行时。断言以安全性换取便利。

const v: unknown = 'hello';
const n = v as number;
console.log(n.toFixed(2)); // runtime error: toFixed is not a function

类型守卫会在运行时验证

类型守卫会实际检查该值。如果检查通过,您和编译器都能确定类型正确——类型收窄背后有真实的运行时测试作为依据。

function toFixed2(v: unknown): string {
  if (typeof v === 'number') return v.toFixed(2);
  return 'N/A';
}
console.log(toFixed2(3.14159), toFixed2('hi'));

自定义类型守卫函数

将复杂检查封装到可复用的守卫中,并让它返回 value is T。整个代码库都能从一次经过充分测试的验证中受益。

type Email = { address: string };
function isEmail(v: unknown): v is Email {
  return typeof v === 'object' && v !== null &&
    'address' in v && typeof (v as any).address === 'string';
}
console.log(isEmail({ address: 'a@b.com' }), isEmail(null));

守卫可以组合和复用

由于守卫是普通函数,您可以组合、测试并复用它们。相比之下,断言是分散的声明,无法集中验证。

function isString(v: unknown): v is string { return typeof v === 'string'; }
function isNonEmpty(v: unknown): v is string {
  return isString(v) && v.length > 0;
}
console.log(isNonEmpty('hi'), isNonEmpty(''));

使用断言注解的断言函数

TypeScript 还提供了断言函数。它们的返回注解使用 asserts 关键字。如果函数正常返回,编译器就会从此处开始收窄参数类型;如果条件不满足,函数就会抛出错误。

function assertNumber(v: unknown): asserts v is number {
  if (typeof v !== 'number') throw new Error('not a number');
}
function use(v: unknown): number {
  assertNumber(v); // after this line, v is number
  return v * 2;
}
console.log(use(21));

断言注解与类型谓词的比较

value is T 守卫会返回一个布尔值,供您进行分支判断。asserts value is T 函数会在失败时抛出错误,并在剩余作用域内收窄类型。两者都有运行时依据,不同于普通的 as。

function assertDefined<T>(v: T): asserts v is NonNullable<T> {
  if (v === null || v === undefined) throw new Error('missing');
}
const maybe: string | null = 'ok';
assertDefined(maybe);
console.log(maybe.length); // narrowed to string

通用断言辅助函数

断言函数非常适合用来定义可复用的前置条件。一个 assert(condition) 辅助函数就可以在整个代码中守护不变量,并在违反条件时尽早抛出错误。

function assert(cond: unknown, msg: string): asserts cond {
  if (!cond) throw new Error(msg);
}
function half(n: number): number {
  assert(n % 2 === 0, 'must be even');
  return n / 2;
}
console.log(half(8));

比较安全性

按安全性从高到低排列:类型守卫和断言函数(经过运行时检查)高于普通的 as 断言(未经检查),而普通断言又高于双重断言(后者很容易造成误导)。请选择符合需求的最安全工具。

// Safe: guard
function safe(v: unknown) {
  return typeof v === 'string' ? v.trim() : '';
}
console.log(safe('  hi  '));

选择合适的工具

当您要根据类型进行分支时,请使用类型守卫。当某个前置条件必须成立,否则就应停止执行时,请使用断言函数。只有在无法进行类型收窄时才使用 as(例如进行 DOM 特化)。

function getInput(v: unknown): asserts v is string {
  if (typeof v !== 'string') throw new Error('expected string');
}
const raw: unknown = 'name';
getInput(raw);
console.log(raw.toUpperCase());

运行时检查更可靠

本课程反复强调的主题是:优先使用运行时检查,而不是断言。守卫和断言函数同时提供编译时类型与运行时安全性,而断言只提供一种声明。

function parsePort(v: unknown): number {
  if (typeof v === 'number' && Number.isInteger(v)) return v;
  throw new Error('invalid port');
}
console.log(parsePort(8080));

快速检查

测试您对断言与类型守卫的理解。

回顾:断言与守卫

您已经学会:

  • 类型守卫(value is T)会在运行时证明类型,并让您进行分支判断。
  • 断言函数(asserts value is T)会在失败时抛出错误,并在之后收窄类型。
  • 普通的 as 断言只会声明类型,不提供运行时安全性。
  • 优先使用经过运行时检查的工具;仅在类型收窄无法处理时使用断言。

下一课程:可选链和空值合并。

function isPositive(v: unknown): v is number {
  return typeof v === 'number' && v > 0;
}
console.log(isPositive(5), isPositive(-1));

常见问题解答

「断言与类型守卫」课时是免费的吗?

是的 — 「断言与类型守卫」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 TypeScript Academy 课程的其余内容,请升级到 CoddyKit PRO。 TypeScript Academy 课程共包含 4 节课。

「断言与类型守卫」这节课中我会学到什么?

在可能的情况下,优先使用运行时检查,而不是断言。 你通过在浏览器中直接运行的动手代码来练习 TypeScript Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 TypeScript Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 TypeScript Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。

「断言与类型守卫」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 TypeScript Academy 课中编写并运行代码吗?

能。每节 TypeScript Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 用于类型断言的 as 关键字
  2. 非空断言运算符
  3. 双重断言及其风险
  4. 断言与类型守卫
← 返回 TypeScript Academy