TypeScript Academy · 课时

根据辨识属性进行收窄

让 TypeScript 在 switch 语句中收窄不同变体。

第 2 / 4 课13 个步骤

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

根据判别属性进行类型收窄

检查判别属性后,TypeScript 会将联合类型收窄为匹配的成员,并开放该成员的特有字段。这正是这种模式的价值所在。

type Shape =
  | { kind: "circle"; radius: number }
  | { kind: "square"; side: number };

function area(s: Shape) {
  if (s.kind === "circle") return Math.PI * s.radius ** 2;
  return s.side ** 2;
}
console.log(area({ kind: "circle", radius: 2 }).toFixed(2));

根据判别属性进行分支选择

使用 switch 检查判别属性,是处理每个变体最清晰的方式。在每个 case 中,类型都会自动收窄。

type Shape =
  | { kind: "circle"; radius: number }
  | { kind: "square"; side: number };

function area(s: Shape): number {
  switch (s.kind) {
    case "circle": return Math.PI * s.radius ** 2;
    case "square": return s.side ** 2;
  }
}
console.log(area({ kind: "square", side: 5 }));

每个分支使用对应成员的字段

在 "circle" 分支中,可以使用 s.radius,但不能使用 s.side。TypeScript 能准确知道当前属于哪个成员。

type Shape =
  | { kind: "circle"; radius: number }
  | { kind: "square"; side: number };

function describe(s: Shape) {
  switch (s.kind) {
    case "circle": return "r=" + s.radius;
    case "square": return "side=" + s.side;
  }
}
console.log(describe({ kind: "circle", radius: 9 }));

基于条件的类型收窄

您不必使用分支选择语句。简单地使用 if 比较判别属性,同样可以有效地进行类型收窄。

type Shape =
  | { kind: "circle"; radius: number }
  | { kind: "square"; side: number };

function perimeter(s: Shape): number {
  if (s.kind === "circle") {
    return 2 * Math.PI * s.radius;
  }
  return 4 * s.side;
}
console.log(perimeter({ kind: "square", side: 3 }));

访问错误字段会失败

在进行类型收窄之前,您不能访问成员特有的字段。TypeScript 会报告错误,因为并非每个成员都具有该属性。

type Shape =
  | { kind: "circle"; radius: number }
  | { kind: "square"; side: number };

function broken(s: Shape) {
  // Error: radius does not exist on Square
  // return s.radius;
  return s.kind;
}
console.log(broken({ kind: "square", side: 1 }));

使用布尔判别属性进行类型收窄

对于 { ok: true } | { ok: false } 联合类型,检查 if (r.ok) 会将类型收窄为成功成员。

type Result =
  | { ok: true; data: string }
  | { ok: false; error: string };

function handle(r: Result): string {
  if (r.ok) return "Data: " + r.data;
  return "Error: " + r.error;
}
console.log(handle({ ok: false, error: "boom" }));

通过提前返回进行类型收窄

针对某个变体提前返回后,剩余代码会收窄为其他变体。这样可以一次处理一个分支,代码也更清晰。

type Shape =
  | { kind: "circle"; radius: number }
  | { kind: "square"; side: number };

function label(s: Shape): string {
  if (s.kind === "circle") return "circle";
  // s is now narrowed to Square here
  return "square with side " + s.side;
}
console.log(label({ kind: "square", side: 8 }));

与其他条件结合

您可以将判别属性检查与其他逻辑结合起来。只要该分支中的判别属性条件仍为真,TypeScript 就会保留类型收窄结果。

type Shape =
  | { kind: "circle"; radius: number }
  | { kind: "square"; side: number };

function bigCircle(s: Shape): boolean {
  return s.kind === "circle" && s.radius > 100;
}
console.log(bigCircle({ kind: "circle", radius: 150 }));

在数组过滤器中进行类型收窄

回调函数内部同样可以进行类型收窄。在这里,我们会在遍历时逐个检查图形。

type Shape =
  | { kind: "circle"; radius: number }
  | { kind: "square"; side: number };

const shapes: Shape[] = [
  { kind: "circle", radius: 1 },
  { kind: "square", side: 2 }
];
shapes.forEach(s => {
  if (s.kind === "circle") console.log("c", s.radius);
  else console.log("s", s.side);
});

分支选择的返回值保持类型安全

当分支选择语句处理并返回每个分支的结果时,TypeScript 会根据所有分支结果的联合类型推断出精确的返回类型。

type Shape =
  | { kind: "circle"; radius: number }
  | { kind: "square"; side: number };

function tag(s: Shape) {
  switch (s.kind) {
    case "circle": return s.radius;
    case "square": return s.side;
  }
}
console.log(tag({ kind: "circle", radius: 4 }));

综合使用类型收窄

无论使用 switch 还是 if,检查判别属性都是安全访问成员字段的关键。接下来,我们将确保每个分支都得到处理。

type Shape =
  | { kind: "circle"; radius: number }
  | { kind: "square"; side: number };

function area(s: Shape): number {
  return s.kind === "circle" ? Math.PI * s.radius ** 2 : s.side ** 2;
}
console.log(Math.round(area({ kind: "circle", radius: 10 })));

快速检查:类型收窄

测试您对判别属性类型收窄的理解。

回顾:根据判别属性进行类型收窄

您已经看到,使用 switch 或 if 检查判别属性,可以将联合类型收窄为一个成员,只暴露该成员的特有字段。提前返回和组合条件都能保留类型收窄结果。

type Shape =
  | { kind: "circle"; radius: number }
  | { kind: "square"; side: number };

const s: Shape = { kind: "square", side: 7 };
console.log(s.kind === "square" ? s.side : 0);
免费开始

用 AI 导师学习 TypeScript — 免费

在浏览器中编写并运行真实代码,获得全天候 AI 导师的即时帮助,并在网页或应用中继续学习。

课程
101
课程
352

常见问题解答

「根据辨识属性进行收窄」课时是免费的吗?

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

「根据辨识属性进行收窄」这节课中我会学到什么?

让 TypeScript 在 switch 语句中收窄不同变体。 你通过在浏览器中直接运行的动手代码来练习 TypeScript Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 TypeScript Academy 需要有经验吗?

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

「根据辨识属性进行收窄」课时需要多长时间?

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

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

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

此课程中的所有课时

  1. 构建可辨识联合
  2. 根据辨识属性进行收窄
  3. 使用 never 进行穷尽性检查
  4. 状态机建模
← 返回 TypeScript Academy