跳转到主要内容
模块 2 · 第 2 课(共 2)课程中的4/14~15 min
模块课程(2/2)

联合和缩小范围

在现实世界中,变量和 API 响应并不总是具有单一的固定类型。 TypeScript 提供联合类型来处理可变性,并提供类型缩小来在运行时安全地对其进行操作。


联合类型

联合类型允许变量接受不同类型的值。它使用竖线 (|) 符号表示:

TS
let result: number | string;
result = 42; // Valid
result = 'Error 404'; // Valid

但是,在使用联合类型时,我们不能直接调用仅属于其中一种类型的方法(例如,如果变量也可以是 number,则我们不能调用 .toUpperCase())。我们首先要“缩小”类型。


类型缩小

类型缩小是 TypeScript 分析控制流结构(例如 if 或 switch)以在运行时推断变量的更具体类型的过程。

有几种方法可以执行缩小:

1. typeof 运算符

区分原始类型的理想选择:

TS
function printLength(value: string | number) {
  if (typeof value === 'string') {
    // TypeScript knows 'value' is a string here
    console.log(value.length);
  } else {
    // TypeScript knows 'value' is a number here
    console.log(value.toFixed(2));
  }
}

2. in 运算符

用于检查对象上是否存在特定属性:

TS
interface Fish {
  swim: () => void;
}
interface Bird {
  fly: () => void;
}

function move(animal: Fish | Bird) {
  if ('swim' in animal) {
    animal.swim(); // Narrowing to Fish
  } else {
    animal.fly(); // Narrowing to Bird
  }
}

受歧视的工会

可区分联合模式包括创建共享具有唯一文字值(称为discriminator)的公共属性的对象。 TypeScript 可以识别这个鉴别器并自动缩小条件块内的类型范围。

TS
interface SuccessResponse {
  status: 'success'; // Literal discriminator
  data: string;
}

interface ErrorResponse {
  status: 'error'; // Literal discriminator
  errorMessage: string;
}

type ApiResponse = SuccessResponse | ErrorResponse;

function handleResponse(response: ApiResponse) {
  if (response.status === 'success') {
    console.log('Data received:', response.data);
  } else {
    console.error('An error occurred:', response.errorMessage);
  }
}

自己尝试一下

练习 1:联合类型

锻炼#ts.m2.l2.e1
尝试:0加载中...

声明一个名为 id 的变量,它可以是数字或字符串。首先使用数字 101 对其进行初始化,然后分配字符串值“USER-101”。

正在加载编辑器...
显示提示

使用 |运算符在 let 变量声明中连接数字和字符串。

3 次尝试后可用的解决方案

练习 2:基本类型缩小

锻炼#ts.m2.l2.e2
尝试:0加载中...

创建一个名为 formatInput 的函数,该函数接受字符串或数字类型的参数输入。如果输入是字符串,则返回转换为大写的输入。如果是数字,则返回输入乘以 2。明确指定类型。

正在加载编辑器...
显示提示

在 if 块内使用 typeof input === 'string' 来分支行为。

3 次尝试后可用的解决方案

练习 3:用“in”缩小范围

锻炼#ts.m2.l2.e3
尝试:0加载中...

给定两个接口 Car(使用drive方法)和Boat(使用方法sail),编写一个名为moveVehicle的函数,它接受Car或Boat类型的参数vehicle。如果车辆具有drive属性,则执行drive()方法。否则,执行 sail() 方法。

正在加载编辑器...
显示提示

在车辆中使用“drive”形式的 in 运算符来缩小界面范围。

3 次尝试后可用的解决方案

练习 4:可区分联合形状

锻炼#ts.m2.l2.e4
尝试:0加载中...

定义一个 Shape 类型,它是两种类型的并集:Circle 和 Square。 Circle 有一个设置为“circle”(文字值)的种类属性和一个半径(数字)。 Square 有一个设置为“square”(文字值)的 kind 属性和一个边(数字)。然后编写一个函数 getArea,它接受 Shape 类型的形状并将面积作为数字返回(对于圆 Math.PI * radius * radius,对于正方形 side * side)。

正在加载编辑器...
显示提示

在 getArea 中使用 shape.kind === 'circle' 来区分类型并计算正确的面积。

3 次尝试后可用的解决方案