谈谈 TypeScript 中的联合类型(union types)和交叉类型(intersection types),它们的应用场景是什么?

news2025/3/18 11:30:55

一、联合类型(Union Types)

核心概念

使用管道符 | 表示多选一关系,典型场景:处理可能存在多种类型的变量

// 基础示例:处理数值型ID(number)或哈希型ID(string)
type EntityID = number | string;

function getEntity(id: EntityID) {
  // 类型守卫处理分支逻辑
  if (typeof id === 'number') {
    console.log(`Fetching by numeric ID: ${id.toFixed(2)}`);
  } else {
    console.log(`Fetching by hash ID: ${id.toUpperCase()}`);
  }
}

实战应用场景

1. 可辨识联合(Discriminated Unions)

通过公共字段实现精确类型推断,适用于状态机等场景

// 图形系统形状定义
type Shape = 
  | { kind: "circle"; radius: number }     // 圆形
  | { kind: "square"; size: number }       // 正方形
  | { kind: "rectangle"; width: number; height: number };  // 长方形

function calculateArea(shape: Shape): number {
  switch (shape.kind) {
    case "circle":
      return Math.PI * shape.radius ​** 2;  // 自动识别radius属性
    case "square":
      return shape.size ​** 2;             // 自动识别size属性
    case "rectangle":
      return shape.width * shape.height;  // 自动识别宽高属性
  }
}
2. 可选参数处理

与 undefined 联用实现可选参数类型定义

// 带缓存的读取函数
type CacheConfig = {
  maxAge: number;
  useLocalStorage?: boolean;
};

function readCache(key: string, config?: CacheConfig) {
  // 类型自动推断为 CacheConfig | undefined
  const effectiveConfig = config || { maxAge: 3600 };
}

开发建议

  1. 优先使用联合类型处理多态数据,比 any 类型更安全
  2. 结合类型守卫(Type Guards)​ 进行精确类型处理
  3. 避免过度宽泛的联合,如 string | number | boolean 建议重构为更具体的联合
  4. 使用类型别名(type)管理复杂联合类型,提升代码可维护性

二、交叉类型(Intersection Types)

核心概念

使用 & 符号实现类型合并,类似接口继承但更灵活

// 基础示例:合并用户基础信息与权限信息
type User = { 
  id: number;
  name: string;
};

type Permission = {
  canEdit: boolean;
  isAdmin: boolean;
};

type UserWithPermission = User & Permission;

const adminUser: UserWithPermission = {
  id: 1,
  name: "Alice",
  canEdit: true,
  isAdmin: true
};

实战应用场景

1. 混入模式(Mixin Pattern)

实现功能组合的最佳实践

// 可序列化能力混入
type Serializable = {
  serialize(): string;
};

class BaseModel {
  constructor(public id: number) {}
}

// 通过交叉类型实现混入
type SerializableModel = BaseModel & Serializable;

const userModel: SerializableModel = {
  ...new BaseModel(1),
  serialize() {
    return JSON.stringify(this);
  }
};
2. 复杂配置合并

合并多个配置类型生成完整配置

// 分阶段配置定义
type BaseConfig = {
  apiEndpoint: string;
  timeout: number;
};

type AuthConfig = {
  clientId: string;
  token: string;
};

type LoggingConfig = {
  logLevel: "debug" | "info";
};

// 生成完整配置类型
type AppConfig = BaseConfig & AuthConfig & LoggingConfig;

const config: AppConfig = {
  apiEndpoint: "/api",
  timeout: 5000,
  clientId: "web-app",
  token: "abc123",
  logLevel: "debug"
};

开发建议

  1. 优先用于对象类型合并,基础类型交叉会产生 never
  2. 替代多接口继承,解决 TS 接口不能多继承的问题
  3. 避免深度嵌套交叉,超过3层的交叉类型建议重构
  4. 与泛型结合 实现灵活的类型操作

三、关键差异与注意事项

类型特性对比

| 特性 | 联合类型(|) | 交叉类型(&) |
|---------------------|------------------------|-----------------------|
| 语义 | 逻辑"或"关系 | 逻辑"与"关系 |
| 适用场景 | 处理不同类型输入 | 合并类型特性 |
| 基础类型操作 | string | number 有效 | string & number => never |
| 对象类型合并 | 创建包含共有属性的类型 | 合并所有属性 |

常见问题处理

1. 类型收缩陷阱
// 危险操作:未进行类型检查直接访问属性
function getLength(input: string | string[]) {
  // 编译错误:未收缩类型时访问length不安全
  return input.length; // Error: Property 'length' does not exist on type 'string | string[]'
  
  // 正确做法:类型断言或类型守卫
  if (typeof input === 'string') return input.length;
  return input.length;
}
2. 交叉类型误用
// 危险操作:基本类型交叉产生 never
type Impossible = string & number;  // 类型为 never

// 实际影响
function handleValue(val: string & number) {
  console.log(val); // 该函数永远无法被调用
}

高级技巧

1. 类型守卫优化
// 自定义类型守卫
function isErrorResponse(
  response: SuccessResponse | ErrorResponse
): response is ErrorResponse {
  return (response as ErrorResponse).error !== undefined;
}

// 使用示例
if (isErrorResponse(res)) {
  console.error(res.error.message);
}
2. 类型分发处理
// 条件类型中的分发特性
type ExtractString<T> = T extends string ? T : never;

// 实际应用
type Result = ExtractString<"hello" | 42 | true>;  // 得到类型 "hello"

四、工程化实践建议

  1. 项目规范
// 建议:独立类型声明文件(types.d.ts)
export type APIResponse<T> = 
  | { status: 'success'; data: T }
  | { status: 'error'; code: number };
  1. 文档注释
/**
 * 用户身份联合类型
 * @typedef {AdminUser | NormalUser} UserRole
 * @property {boolean} AdminUser.isSuperAdmin - 超级管理员标识
 * @property {string} NormalUser.department - 所属部门
 */
type UserRole = AdminUser | NormalUser;
  1. 性能优化
// 避免过度使用交叉类型
// 不推荐:超过3层的交叉类型
type OverComplex = A & B & C & D;

// 推荐:使用接口继承重构
interface Combined extends A, B, C, D {}

总结

联合类型与交叉类型共同构成了TS类型系统的核心武器库。

联合类型(Union Types)擅长处理不确定性输入,交叉类型(Intersection Types)专注解决确定性的类型组合

掌握二者的本质区别与适用边界,配合类型守卫等辅助手段,能够大幅提升代码的类型安全性。

在实际项目中,建议将复杂类型操作限制在系统边界层(如API响应处理),保持核心业务逻辑的类型简洁性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2317192.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

✎ 一次有趣的经历

&#x1f4c6;2025年3月17日 | 周一 | ☀️晴 &#x1f4cd;今天路过学院楼7&#xff0c;见到了满园盛开的花&#x1f33a;&#xff0c;心情瞬间明朗&#xff01; &#x1f4cc;希望接下来的日子也能像这些花一样&#xff0c;充满活力&#x1f525;&#xff01; &#x1…

快!快!快!NDPP时延测试数据公布!

在全方位认识NDPP第3期《NDPP在金融场景的应用》中&#xff0c;我们重点介绍了NDPP的典型应用场景行情解码硬件加速和策略计算加速&#xff0c;并帮助某百亿私募用户基于NDPP实现期货业务加速的案例。 近期&#xff0c;中科驭数凭借低时延产品荣获信创“大比武”行业融合赛道三…

激光雷达“开卷”2.0,头部Tier1入局

高阶智驾的普及&#xff0c;正在催生激光雷达市场的巨大潜在增长空间。 本周&#xff0c;汽车激光雷达主力供应商之一的禾赛科技发布财报&#xff0c;去年第四季度激光雷达总交付量为222,054台&#xff0c;同比增长153.1%&#xff0c;超过2023年全年。2024全年激光雷达总交付量…

力扣No.376.摆动序列

题目&#xff1a; 链接&#xff1a; https://leetcode.cn/problems/wiggle-subsequence/description/ 代码&#xff1a; class Solution {public int wiggleMaxLength(int[] nums) {int nnums.length;//状态表示:int[] fnew int[n];int[] gnew int[n];//初始化:for(int i0;i…

C语言中qsort函数的详解,以及模拟

引言 C语言中qsort函数的详解和模拟实现qsort函数&#xff0c;这里为了使用冒泡排序来模拟qsort函数 一、详解qsort函数 在 C 语言中&#xff0c;qsort 函数是一个标准库函数&#xff0c;用于对数组进行快速排序&#xff08;Quick Sort&#xff09;。它位于 <stdlib.h>…

9、讲一讲你理解的虚拟内存【中高频】

计算机早期&#xff0c;CPU 是直接操作 物理内存&#xff08;Physical Memory&#xff09;的&#xff0c;但这会导致 内存空间无法完全隔离&#xff0c;一个程序修改了另一个程序的地址空间&#xff0c;就会导致程序崩溃&#xff1b;同时物理内存大小有限&#xff0c;一旦超出这…

算法刷题整理合集(四)

本篇博客旨在记录自已的算法刷题练习成长&#xff0c;里面注有详细的代码注释以及和个人的思路想法&#xff0c;希望可以给同道之人些许帮助。本人也是算法小白&#xff0c;水平有限&#xff0c;如果文章中有什么错误或遗漏之处&#xff0c;望各位可以在评论区指正出来&#xf…

高数1.5 极限的运算法则

1. 预备知识 2.四则求极限法则 3.复合运算求极限法则

【鸿蒙开发】Hi3861学习笔记- 定时器中断

00. 目录 文章目录 00. 目录01. 概述02. 定时器相关API2.1 hi_timer_create2.2 hi_timer_start2.3 hi_timer_stop2.4 hi_timer_delete 03. 硬件设计04. 软件设计05. 实验现象06. 附录 01. 概述 定时器&#xff0c;顾名思义就是用来计时的&#xff0c;我们常常会设定计时或闹钟…

Power Apps 技术分享:画布应用使用表单控件

前言 表单控件&#xff0c;是画布应用里一个非常好用的控件&#xff0c;我们今天简单介绍下&#xff0c;如何使用这个控件。 正文 1.首先&#xff0c;我们需要有一个数据源&#xff0c;我们这里用上一篇博客新建的数据源&#xff0c;如下图&#xff1a; 2.新建一个页面&#xf…

【数据库】Data Model(数据模型)数据模型分析

理解图片中的 Data Model&#xff08;数据模型&#xff09;是学习数据库设计和应用程序开发的重要一步。作为初学者&#xff0c;你可以通过比喻和简单的解释来理解这些概念以及它们之间的联系。以下是对图片中数据模型的详细分析&#xff0c;以及如何理解它们之间的关系。 1. 数…

【Unity】 HTFramework框架(六十二)Agent编辑器通用智能体(AI Agent)

更新日期&#xff1a;2025年3月14日。 Github源码&#xff1a;[点我获取源码] Gitee源码&#xff1a;[点我获取源码] 索引 编辑器通用智能体AIAgent类Friday&#xff08;星期五&#xff09;启用智能体设置智能体类型开放智能体权限智能体交互资源优化批处理运行代码联网搜索休闲…

学习笔记:黑马程序员JavaWeb开发教程(2025.3.17)

11.5 案例-文件上传-阿里云OSS-入门 出现报错&#xff1a;Process exited with an error: 1 (Exit value: 1)&#xff0c;点击exec那一行&#xff0c;出现错误原因&#xff1a;Command execution failed. 在CSDN上找到了解决方法&#xff1a; 之后出现新的报错&…

仿最美博客POETIZE(简易版)

写在前面 本文章参考于两个开源项目分别为&#xff1a;POETIZE-最美博客&#xff0c;拾壹博客 如有侵权&#xff0c;请联系删除 正题 此页面为拾壹博客修改而成&#xff0c;采用了POETIZE的布局以及背景图片&#xff0c;技术栈:SpringbootVue&#xff0c;主要涉及页面为网站…

STM32——独立看门狗(IWDG)

IWDG 简介 独立看门狗本质上是一个 定时器 &#xff0c;这个定时器有一个输出端&#xff0c;可以输出复位信号。该定时器是一个 12 位的递减计数器 &#xff0c;当计数器的值减到 0 的时候&#xff0c;就会产生一个复位信号。如果 在计 数没减到 0 之前&#xff0c;重置计…

C++11智能指针简述

一、实现原理 在智能指针对象中有一个裸指针&#xff0c;此指针存储的是动态创建对象的地址&#xff0c;用于生存期控制&#xff0c;能够确保智能指针对象离开所在作用域时&#xff0c;自动正确地销毁动态创建的对象&#xff0c;防止内存泄漏。 使用裸指针存在的问题&#xff…

Linux操作系统实验报告单(3)文本编辑器vi/vim

一、实验目的 掌握vi/vim编辑器的进入和退出方式了解vi/vim的三种模式熟练vi/vim的操作命令 二、实验内容 1.在家目录下新建一个名为“vitest_name”&#xff08;“name”为学生姓名拼音&#xff09;的目录。 ●创建用户目录命令&#xff1a;sudo mkdir /home/vitest_lw3613 …

Centos固定IP配置

虚拟机安装 安装vmware 网盘链接 安装centos7.5 网盘链接 安装教程自行查找 固定IP配置 对安装好的VMware进行网络配置&#xff0c;方便虚拟机连接网络&#xff0c;本次设置建议选择NAT模式&#xff0c;需要宿主机的Windows和虚拟机的Linux能够进行网络连接&#xff0c;…

二叉树算法题实战:从遍历到子树判断

目录 一、引言 二、判断两棵二叉树是否相同 思路 代码实现 注意点 三、二叉树的中序遍历 思路 代码实现 注意点 四、判断一棵树是否为另一棵树的子树 思路 代码实现 注意点 ​编辑 五、补充 一、引言 作者主页&#xff1a;共享家9527-CSDN博客 作者代码仓库&am…

学习threejs,使用MeshFaceMaterial面材质容器

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言1.1 ☘️THREE.MeshFaceMaterial 二…