基于本文回答

播面 播面

刷题像听歌,多听自然懂
0
评论

联合类型 (Union Types) 和交叉类型 (Intersection Types)?

知识点图片

在 TypeScript 中,联合类型 (Union Types)交叉类型 (Intersection Types) 是两种非常重要的组合类型的方式。它们允许你通过组合现有的类型来创建新的类型。

简单来说:

  • 联合类型 (|):表示“”的关系(是 A 或者 是 B)。
  • 交叉类型 (&):表示“”的关系(既是 A 又是 B,通常用于合并)。

1. 联合类型 (Union Types)

符号: |

联合类型表示一个值可以是几种类型之一。

基本用法

最常见的场景是允许一个变量接受不同类型的值(例如 stringnumber)。

typescript
// id 可以是数字,也可以是字符串
let id: number | string;

id = 101;       // OK
id = "202-A";   // OK
// id = true;   // Error: 不能将 boolean 赋值给 number | string

访问成员的限制

当你使用联合类型时,TypeScript 只能保证该变量拥有这些类型共有的成员。

typescript
function printId(id: number | string) {
  // console.log(id.toUpperCase()); // Error: number 类型没有 toUpperCase 方法
  
  console.log(id.toString()); // OK: toString 是 string 和 number 共有的方法
}

类型守卫 (Type Guards)

为了安全地使用特定类型的方法,你需要使用“类型守卫”来缩小类型范围(Narrowing)。

typescript
function printId(id: number | string) {
  if (typeof id === "string") {
    // 在这个块里,TS 知道 id 是 string
    console.log("ID is string: " + id.toUpperCase());
  } else {
    // 在这个块里,TS 知道 id 是 number
    console.log("ID is number: " + id.toFixed(2));
  }
}

字面量联合类型

常用于限制变量只能是某几个特定的值(类似枚举)。

typescript
type Direction = 'up' | 'down' | 'left' | 'right';
type WindowStates = "open" | "closed" | "minimized";

2. 交叉类型 (Intersection Types)

符号: &

交叉类型将多个类型合并为一个类型。这就意味着这个类型的对象同时拥有了这几种类型的所有成员。

基本用法

常用于对象类型的合并(Mixins)或扩展接口。

typescript
interface Person {
  name: string;
  age: number;
}

interface Employee {
  employeeId: number;
  department: string;
}

// Staff 类型同时拥有 Person 和 Employee 的所有属性
type Staff = Person & Employee;

const newStaff: Staff = {
  name: "Alice",      // 来自 Person
  age: 30,            // 来自 Person
  employeeId: 12345,  // 来自 Employee
  department: "IT"    // 来自 Employee
};

同名属性冲突

如果两个类型有相同的属性名,但类型不同,交叉后的结果通常是 never(因为一个值不可能同时是两种冲突的类型)。

typescript
interface A {
  id: string;
}

interface B {
  id: number;
}

type C = A & B;

// const c: C = { id: ... } 
// Error: id 的类型变成了 string & number,即 never。
// 你无法给 id 赋值,因为没有值既是 string 又是 number。

3. 总结与对比

特性 联合类型 (A | B) 交叉类型 (A & B)
逻辑关系 OR (或) AND (和)
含义 值是 A 类型 或者 B 类型 同时包含了 A 和 B 的所有特性
属性访问 只能直接访问 A 和 B 的公共属性 可以访问 A 和 B 的所有属性
主要用途 处理多种可能的输入类型 (如 API 响应) 组合对象、扩展功能、混入 (Mixins)
类比 像“多选一”开关 像“拼图”,把两块拼在一起

4. 实际应用场景示例

场景 A:API 响应 (联合类型)

API 可能返回成功的数据,也可能返回错误信息。

typescript
interface SuccessResponse {
  status: 'success';
  data: { id: number; name: string };
}

interface ErrorResponse {
  status: 'error';
  message: string;
}

// 响应可能是成功,也可能是失败
type ApiResponse = SuccessResponse | ErrorResponse;

function handleResponse(res: ApiResponse) {
  // 利用 status 字段作为可辨识联合 (Discriminated Union)
  if (res.status === 'success') {
    console.log(res.data.name); // TS 知道这里是 SuccessResponse
  } else {
    console.error(res.message); // TS 知道这里是 ErrorResponse
  }
}

场景 B:React 组件 Props (交叉类型)

当你编写一个 UI 组件库时,想让你的组件支持原生 HTML 属性。

typescript
// 自定义属性
interface ButtonProps {
  variant: 'primary' | 'secondary';
  isLoading?: boolean;
}

// 将自定义属性与原生 button 标签的属性合并
// React.ComponentProps<'button'> 包含了 onClick, className, id 等所有原生属性
type Props = ButtonProps & React.ComponentProps<'button'>;

// 现在这个 props 既有 variant,又有 onClick
const MyButton = (props: Props) => { ... }
00:00
00:00