前端进阶之旅前端进阶之旅
  • 基础篇HTML/CSS/JS 打底
  • 进阶篇原理与工程化
  • 高频篇面试最常问的那批
  • 精选篇按模块收敛的总结
  • 手写篇常考代码手写实现
  • 面经篇真实面试问题复盘
  • AI 篇NEWAI 时代的前端考点
  • 历年面经NEW按年份追踪真实考点
  • 每日一题每天一道,攒手感
  • 专项自测100 题快速查漏
  • 小程序题库小程序专项刷题
  • 算法题库NEW在线编码即时判题
  • 知识卡片NEW碎片时间过考点
  • 面试题大全常见问题解析
  • AI 答疑NEW随时提问,即时解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • AI 定制路线NEW按你的简历现排
  • AI 知识地图NEW串起全站知识点
  • 原理篇React / Vue 源码拆解
  • HTTP从报文一路讲到 HTTPS
  • 浏览器渲染、事件循环、进程
  • 计算机基础Linux、网络、操作系统
  • 设计模式23 种模式怎么用
  • Node学习指南从环境搭建到服务端
  • NPM工作流script、依赖与发布
  • Docker容器化部署上手
  • Canvas图形与动画实战
  • 前端系统进阶学习大型项目工程化
  • 前端综合文章长期沉淀的实践文
  • 思维导图知识点全景图
  • 学习路线按图索骥不跑偏
  • AI 热点NEWAI 每日动态
  • 公众号动态公众号历史文章
  • 博客动态站长的技术博客
  • 开发者导航常用工具与文档站
  • 基础篇HTML/CSS/JS 打底
  • 进阶篇原理与工程化
  • 高频篇面试最常问的那批
  • 精选篇按模块收敛的总结
  • 手写篇常考代码手写实现
  • 面经篇真实面试问题复盘
  • AI 篇NEWAI 时代的前端考点
  • 历年面经NEW按年份追踪真实考点
  • 每日一题每天一道,攒手感
  • 专项自测100 题快速查漏
  • 小程序题库小程序专项刷题
  • 算法题库NEW在线编码即时判题
  • 知识卡片NEW碎片时间过考点
  • 面试题大全常见问题解析
  • AI 答疑NEW随时提问,即时解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • AI 定制路线NEW按你的简历现排
  • AI 知识地图NEW串起全站知识点
  • 原理篇React / Vue 源码拆解
  • HTTP从报文一路讲到 HTTPS
  • 浏览器渲染、事件循环、进程
  • 计算机基础Linux、网络、操作系统
  • 设计模式23 种模式怎么用
  • Node学习指南从环境搭建到服务端
  • NPM工作流script、依赖与发布
  • Docker容器化部署上手
  • Canvas图形与动画实战
  • 前端系统进阶学习大型项目工程化
  • 前端综合文章长期沉淀的实践文
  • 思维导图知识点全景图
  • 学习路线按图索骥不跑偏
  • AI 热点NEWAI 每日动态
  • 公众号动态公众号历史文章
  • 博客动态站长的技术博客
  • 开发者导航常用工具与文档站
首页程序员面试题库TypeScript 联合类型 交叉类型 区别
TyTypeScript类型系统基础

TypeScript 联合类型与交叉类型有什么区别,为什么字段越多反而更严格?

联合扩大可接受的候选,交叉要求同时满足约束;观察字段数量时容易把这个方向想反。

前端进阶之旅 · 一题精讲更新于 2026.09.06
TypeScript#类型系统基础#类型系统
先看核心答案读代码示例
理解线索

用可接受值理解两个符号

  1. 联合符号候选可以来自任一成员类型
  2. 交叉符号同一个值必须满足所有成员类型
  3. 使用能力能够安全读取什么由当前证明决定

字段并集与值集合不是同一个观察角度,面试回答应先说明正在比较哪一层。

核心回答

先记住这个答案

A | B 表示值可以满足 A 或 B,使用前只能依赖当前已证明可用的能力;A & B 表示值必须同时满足两者。对象交叉常常拥有双方要求的字段,因此可接受的对象反而更受限制。联合不等于把所有字段都变成可选,交叉也不等于后写属性覆盖前写属性。发生同名字段冲突时,字段必须同时满足两种类型,可能得到 never,某些判别字段冲突还可能使整个交叉无法成立。

  • 联合接受任一分支,分支能力需要收窄后使用
  • 交叉要求同时满足约束,不执行后值覆盖
  • 类型运算不会在运行时创建或合并对象

为什么联合不能直接读取所有字段

一个函数接收带链接的项目或带动作的项目,运行时不保证当前项目同时拥有两者。联合保留了两种候选,所以访问特有字段前必须判断分支。公共字段只有在所有候选都支持相关操作时,才可以直接按公共契约使用。

示例使用属性存在判断区分两种输入。交叉参数则明确要求同一个对象同时拥有链接与动作,函数可以依次使用它们。区别来自函数承担的输入契约,不是由竖线表示弱检查、与号表示高级检查这样的口号决定。

任一能力与同时具备能力TypeScript
type LinkItem = { href: string };
type ActionItem = { run: () => void };
function useEither(item: LinkItem | ActionItem) {
  if ('href' in item) return item.href;
  item.run();
  return 'action';
}
function useBoth(item: LinkItem & ActionItem) {
  item.run();
  return item.href;
}
useEither({ href: '/docs' });
// @ts-expect-error 交叉类型还要求 run
useBoth({ href: '/docs' });

只有链接的对象可以满足联合,却不能满足交叉。交叉不会自动补出动作函数,联合分支中的读取则依赖实际判断所建立的类型证据。

交叉为什么不是对象展开

JavaScript 对象展开遇到同名属性通常由后面的值覆盖前面的值,这是运行时构造对象的规则。类型交叉没有覆盖顺序:如果同一个字段同时要求字符串和数字,它必须同时满足两个互不相交的集合,因此该字段可能变成 never。

若想描述先删除旧字段再替换类型,通常应明确使用 Omit 去掉冲突键,再组合新定义。这样的类型设计表达替换意图,也方便审阅者发现契约变化。直接叠加交叉可能把错误拖到后续构造对象或调用函数时才暴露。

业务状态不要用可选字段拼凑联合

把成功数据和失败原因都写成可选字段,会允许成功没有数据、失败却带着成功数据等无意义组合。更清楚的方式是让各个成员分别拥有自己的必需字段,再用具体状态标签关联它们,读取时根据标签收窄。

交叉适合组合确实同时存在的能力,例如实体标识与审计字段,但不能证明服务器真的提供这些数据。外部 JSON 仍需要解析验证;只把响应断言成复杂交叉类型,会让错误看起来消失,实际读取时仍可能遇到缺失字段。

回答前,多想一步

容易答错的地方

联合就是把双方字段全部设成可选
联合保留成员各自的完整约束,可选字段大对象会允许原本不存在的组合,可能破坏状态与数据之间的重要关联。
交叉里后面的字段会覆盖前面的字段
类型交叉要求同时满足两边,同名字段不会按书写顺序覆盖;需要替换字段时应显式移除旧键并声明新契约。
试着用自己的话回答

面试官还会怎么问?

string 与 number 的交叉有什么值?

在正常类型语义下没有同时属于两者的值,结果为 never;这与字符串或数字的联合允许两类值恰好形成对照。

交叉两个对象一定会让整个类型变成 never 吗?

不会。无冲突字段可以正常组合,普通冲突可能只让某个属性成为 never,判别属性等情况才可能让整个交叉被归约为 never。

联合成员共享字段就能随便调用其方法吗?

还要看共享字段的类型是否支持该操作;字段可能仍是联合类型,只有所有可能值都安全支持的操作才可以直接使用。

从一道题,走向一组知识

把知识连起来

类型系统基础

TypeScript interface extends 和交叉类型 & 组合对象时有什么区别?

比较接口继承与交叉面对冲突字段时的反馈

类型收窄

TypeScript 判别联合如何建模,为什么标签写成 string 后不能正确收窄?

用状态标签保留联合成员与数据之间的关联

参考资料

  • TypeScript:Union Types
  • TypeScript:Intersection Types

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. 为什么联合不能直接读取所有字段
  3. 交叉为什么不是对象展开
  4. 业务状态不要用可选字段拼凑联合
  5. 容易答错的地方
  6. 面试官还会怎么问
  7. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑