发布于 2026-01-06 3 阅读
0

TypeScript 中使用可区分联合类型可以实现更好的类型定义

TypeScript 中使用可区分联合类型可以实现更好的类型定义

我们在 TypeScript 中定义类型的方式会影响 TypeScript 在错误发生时发出警告的有效性。如果我们采用宽泛的方法,即用一个类型涵盖多种类型,最终会削弱 TypeScript 的功能,降低其有效性。

类型定义越具体,TypeScript 就能越有效地捕获潜在错误。本文将探讨如何使用判别式联合来编写更好、更具体的类型,从而让 TypeScript 更好地为我们服务。

我们举个最简单的例子——形状。形状包括圆形、矩形、正方形等等;你应该明白我的意思。你不可能找到一个单一的类型别名,既能涵盖所有形状,又不会有所妥协。

如果我们只为以上三种形状定义Shape类型别名,就需要考虑并非所有形状都包含所有字段的情况,例如,圆形只有半径,而矩形和正方形都没有半径;圆形本身也没有宽度和高度。可想而知,随着形状数量的增加,问题只会越来越严重。

所以,我们的类型别名看起来会是这样。

type Shape = {
  radius?: Number; // Circle
  length?: Number; // Rectangle
  width?: Number; // Rectangle
  side?: Number; // Square side Length
}
Enter fullscreen mode Exit fullscreen mode

就上述示例而言,我假设正方形不能设置高度和宽度。

如您所见,上面的类型别名不太有用,因为如果您有一个圆圈,您可以很容易地省略所有字段或将它们全部添加到圆圈中,Shape而 TypeScript 将完全无法帮助您。

对于第三方 SDK 来说,这尤其不是一个好做法,因为你必须不断查阅文档才能了解所处理数据的结构。类型可以帮助我们避免犯一些愚蠢且本可避免的错误,而这些错误是我们作为人类都会犯的,因为这是人之常情。

此外,我们也失去了缩小类型范围的能力。要将上述类型缩小为圆形、矩形或正方形并不容易。

类型缩减是指将类型从精度较低的类型转换为精度较高的类型。您可以在这里了解更多关于类型缩减的信息。

受歧视的工会

可区分类型联合是指利用代码流分析将一组潜在对象简化为一个特定对象。——TypeScript文档

现在,我来提供一个可能的解决方案。我们首先定义三个不同的类型别名。每个类型别名都有一个字面值类型成员属性——shape用于区分其对应的形状,即RectangleCircle以及Square我们每个形状。

type Square = {
  shape: "Square";
  side: number;
}

type Rectangle = {
  shape: "Rectangle",
  length: number;
  width: number;
}

type Circle = {
  shape: "Circle"
  radius: number;
}
Enter fullscreen mode Exit fullscreen mode

然后我们可以使用这三个的联合来声明一个形状为 `shape` 的类型别名,该别名只能是上述三种类型中的一种。

type Shape = Square | Rectangle | Circle;
Enter fullscreen mode Exit fullscreen mode

类型Shape别名只能是 Square、Rectangle 或 Circle。

你可能会问,上述方法的优势是什么?

强类型形状

第一个优势是,与之前的解决方案相比,我们现在针对每种形状都实现了强类型化。例如,如果您将形状指定为圆形,那么我们只需要提供半径,如果缺少半径,TypeScript 会抛出错误。

const x: Shape = {
  shape: "Circle",
  radius: 5,
  width: 5, // Error ---> Object literal may only specify known properties, and 'width' does not exist in type 'Circle'.
}
Enter fullscreen mode Exit fullscreen mode

如上所示,一旦你将形状属性指定为Circle,那么你就只能指定Circle类型别名中可用的属性。

尝试添加不存在的字段将导致以下错误:// Error ---> Object literal may only specify known properties, and 'width' does not exist in type 'Circle'.

现在可以进行类型缩小了。

现在可以使用 literal 属性进行类型缩小shape

if(shape.shape === "Circle") {
  // the type is now a Circle only
}
Enter fullscreen mode Exit fullscreen mode

点击这里了解更多关于TypeScript中的类型缩减的信息

结论

在本文中,我们学习了如何使用可区分联合类型在 TypeScript 中编写更具体的类型,从而获得更完善的类型系统,并提升开发者的体验。这反过来又使我们能够编写更类型安全的代码,帮助 TypeScript 消除许多原本可能被忽略的代码错误。

如果您觉得这篇文章对您有所帮助,并想继续学习 TypeScript,请访问我的 TypeScript 系列文章——《TypeScript 入门指南》 (A Byte of TypeScript)。《TypeScript 入门指南》是我将定期更新的一个新系列,旨在帮助您揭开 TypeScript 的神秘面纱。

文章来源:https://dev.to/this-is-learning/better-types-using-discriminated-unions-in-typescript-4i3g