TypeScript 联合类型

TypeScript联合类型详解 – 编程小白指南

TypeScript联合类型详解

编程小白的TypeScript联合类型知识手册

一、联合类型是什么?

联合类型是TypeScript中的一个强大特性,它允许你定义一个变量可以是多种类型中的一种。

🔍 大白话解释:

想象你有一个盒子,这个盒子可以装苹果🍎或者香蕉🍌,但不能同时装两种水果。联合类型就像是给这个盒子贴上一个标签:”苹果 | 香蕉”,告诉别人这个盒子只能放这两种水果中的一种。

// 定义一个变量可以是number或string类型
let age: number | string;

age = 25; // 正确,number类型
age = “二十五”; // 正确,string类型
age = true; // 错误!boolean类型不符合要求

二、联合类型的基本用法

1. 定义联合类型

使用竖线 | 分隔多个类型:

type ID = number | string; // ID可以是数字或字符串

let userId: ID = 123; // 正确
let orderId: ID = “ORD-456”; // 正确

2. 联合类型与函数参数

函数参数使用联合类型时,可以接受多种类型的值:

function printId(id: number | string) {
  console.log(`ID: ${id}`);
}

printId(101); // 正确
printId(“C101”); // 正确

⚠️ 重要提示:

当你使用联合类型时,只能访问这些类型共有的方法和属性。

function getLength(value: string | number) {
  // 错误!因为number类型没有length属性
  console.log(value.length);
}

上面代码会报错,因为number类型没有length属性。

三、类型守卫 – 安全使用联合类型

为了解决上面提到的问题,我们需要使用类型守卫来缩小类型范围。

1. typeof 类型守卫

使用JavaScript的typeof操作符检查类型:

function getLength(value: string | number) {
  if (typeof value === “string”) {
    // 这里value被确定为string类型
    console.log(value.length);
  } else {
    // 这里value被确定为number类型
    console.log(value.toString().length);
  }
}

2. 自定义类型守卫

对于自定义类型(如接口),可以使用in操作符:

interface Circle {
  kind: “circle”;
  radius: number;
}

interface Square {
  kind: “square”;
  sideLength: number;
}

type Shape = Circle | Square;

function getArea(shape: Shape) {
  if (shape.kind === “circle”) {
    // 这里shape被确定为Circle类型
    return Math.PI * shape.radius ** 2;
  } else {
    // 这里shape被确定为Square类型
    return shape.sideLength ** 2;
  }
}

💡 小贴士:

上面的例子使用了可辨识联合模式,通过公共的kind属性来区分不同的类型。

四、联合类型的高级用法

1. 联合类型与数组

可以创建包含多种类型元素的数组:

// 数组元素可以是数字或字符串
let mixedArray: (number | string)[] = [1, “two”, 3, “four”];

// 访问元素时,TypeScript会提示联合类型的方法
mixedArray[0].toString(); // 正确,所有类型都有toString方法
mixedArray[1].toFixed(2); // 错误!字符串没有toFixed方法

2. 联合类型与类型别名

结合使用type关键字,让代码更清晰:

type Status = “pending” | “approved” | “rejected”;

function handleStatus(status: Status) {
  // 这里只能传入上面定义的三种字符串之一
  console.log(`当前状态:${status}`);
}

handleStatus(“pending”); // 正确
handleStatus(“processing”); // 错误!

3. 联合类型与字面量类型

联合类型可以包含具体的值,这称为字面量类型:

type DiceValue = 1 | 2 | 3 | 4 | 5 | 6;

function rollDice(): DiceValue {
  return (Math.floor(Math.random() * 6) + 1) as DiceValue;
}

let dice: DiceValue = 4; // 正确
dice = 7; // 错误!只能是1-6之间的数字

🌰 实际应用示例:

联合类型在React组件中非常有用:

type ButtonSize = “small” | “medium” | “large”;
type ButtonType = “primary” | “secondary” | “danger”;

interface ButtonProps {
  size?: ButtonSize;
  type?: ButtonType;
  onClick: () => void;
  children: React.ReactNode;
}

const Button: React.FC<ButtonProps> = ({ size = ‘medium’, type = ‘primary’, …props }) => {
  // 组件实现…
}

五、常见问题与解决方案

1. 类型守卫不够严谨

function printValue(value: string | number | boolean) {
  if (typeof value === “string”) {
    console.log(value.toUpperCase());
  } else if (typeof value === “number”) {
    console.log(value.toFixed(2));
  }
  // 忘记了处理boolean类型!
}

解决方案: 使用更严格的条件判断或添加default分支

2. 类型断言过度使用

let input: string | number = “123”;

// 强制类型断言,但可能不安全
let length: number = (input as string).length;

解决方案: 尽量使用类型守卫代替类型断言

3. 联合类型与重载混淆

⚠️ 注意:

联合类型不同于函数重载:

• 联合类型:一个参数可以是多种类型

• 函数重载:多个函数签名,根据参数类型决定调用哪个实现

六、最佳实践

  1. 优先使用联合类型而不是any类型,保持类型安全
  2. 对超过3种的联合类型考虑使用可辨识联合模式
  3. 使用类型别名给复杂联合类型命名,提高可读性
  4. 处理联合类型时,始终包含所有可能的类型分支
  5. 在React中,联合类型非常适合组件的状态和属性定义

💡 小贴士:

使用VS Code等编辑器时,悬停在联合类型变量上可以查看所有可能的类型,这对开发非常有帮助!

TypeScript联合类型知识点总结 | 编程小白友好指南 | 建议收藏保存

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

滚动至顶部