前端进阶之旅前端进阶之旅
  • 基础篇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 interface extends 交叉类型 冲突字段
TyTypeScript类型系统基础

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

两种写法都能表达组合,真正影响维护体验的是冲突在哪里被发现,以及组合是否仍有合法值。

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

先分清扩展与替换

  1. 兼容扩展新增能力同时保留基础使用者的期待
  2. 约束交叉把两个条件一起施加给同一个值
  3. 字段替换移除原有键后声明新的字段契约

同名字段出现不同类型时,应先审查业务意图,而不是寻找不报错的拼接语法。

核心回答

先记住这个答案

interface extends 表达一个接口满足基础接口的契约,继承时的冲突通常会直接报错;交叉类型 A & B 要求同时满足两边,即使组合语法成立,同名属性也可能变成无法构造的 never。接口适合有稳定成员、明确扩展关系的公开契约,交叉便于组合已有类型表达式。两者都不会提供运行时继承或复制实现。需要改变某字段含义时,先检查是否真是兼容扩展;如果是替换,应明确移除旧键再定义,避免制造隐藏冲突。

  • 接口扩展会检查继承契约是否相容
  • 交叉可以延后暴露无法满足的字段约束
  • 类型组合不会复用任何运行时方法实现

接口继承为什么尽早拒绝冲突

基础接口声明标识是字符串,下游就可能直接调用字符串方法。扩展接口如果改成数字,就无法再作为基础接口使用,因此继承声明应当失败。多个基础接口存在不一致成员时也可能在扩展处报错,帮助作者定位冲突来源。

交叉别名则可以写出同时要求字符串与数字的标识。这不表示编译器接受了任意一种标识,而是字段被压缩成没有正常值的类型。示例保留这种差异,并展示显式替换字段的写法,让改变契约的意图出现在声明处。

冲突继承与不可满足的交叉字段TypeScript
interface Entity { id: string }
// @ts-expect-error 数字 id 不满足 Entity 的字符串契约
interface NumericEntity extends Entity { id: number }
type Conflicted = Entity & { id: number };
type ImpossibleId = Conflicted['id'];
// @ts-expect-error id 需要同时满足 string 和 number
const invalid: Conflicted = { id: 1 };
type Replaced = Omit<Entity, 'id'> & { id: number };
const replaced: Replaced = { id: 1 };

继承冲突在声明处被拒绝,交叉别名本身可定义,但数字对象不能构造它。Replaced 明确删除旧 id 后再定义数字字段,因此它是一份新契约而非原接口的兼容扩展。

为什么不能随意继承联合类型

普通接口需要能够静态确定成员的对象类型作为继承基础。若基础是两个不同对象的联合,成员到底属于哪个分支并不固定,直接 extends 这样的联合会受到限制。需要保留候选分支时,通常继续使用类型别名组织联合与交叉。

类型别名还可以命名原始值、元组和条件类型等表达式,接口则围绕对象契约并支持声明合并。选择不必变成风格争论:先看需要表达的类型是否适用,再考虑公开扩展、错误定位和团队维护方式,避免为了统一写法扭曲模型。

组合很多层后怎样定位错误

看到某属性成为 never,可以沿交叉成员逐个查找该键的来源,检查是否有字符串与数字、互斥字面量等冲突。不要立即用断言构造值,否则下一层调用仍可能要求不可满足的条件。必要时把复杂表达式拆成有意义的中间别名。

公开配置类型增加一个交叉成员也可能使既有调用者突然无法赋值,尤其是插件类型碰巧使用了同名键。评审时应检查实际字段重叠和代表性调用,不能只验证类型声明文件本身能编译;错误常常发生在消费端构造对象的地方。

回答前,多想一步

容易答错的地方

交叉没有在声明处报错就代表组合合理
它可能把冲突保留为 never 属性,直到创建对象或使用接口时才暴露;应验证真实调用样例能否满足组合后的契约。
extends 会自动继承方法实现
接口只存在于类型层,声明的方法不会生成可运行的函数;复用实现需要类继承、对象组合或普通函数等运行时机制。
试着用自己的话回答

面试官还会怎么问?

同名字段缩小为合法子类型可以吗?

兼容的缩小可能满足基础契约,例如把字符串字段收窄为特定字面量;仍应检查写入语义和可变别名是否符合实际使用预期。

Omit 后重定义还可以当原接口使用吗?

只有替换后的字段继续满足原契约时才可以;把字符串改为数字就不再兼容,使用 Omit 不会自动建立这种替换的安全性。

为什么有时整个交叉会变成 never?

编译器会对某些互斥判别字段进行整体归约,具体结果需要结合成员形状查看;不能把所有同名字段冲突都概括为相同表现。

从一道题,走向一组知识

把知识连起来

类型系统基础

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

从值集合角度理解同时满足约束为何产生冲突

类型系统基础

TypeScript 如何用 never 检查 switch 是否处理了全部联合分支?

对照 never 在不可达分支中的实际用途

参考资料

  • TypeScript:Interface Extension vs. Intersection

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

本题目录
  1. 先记住这个答案
  2. 接口继承为什么尽早拒绝冲突
  3. 为什么不能随意继承联合类型
  4. 组合很多层后怎样定位错误
  5. 容易答错的地方
  6. 面试官还会怎么问
  7. 把知识连起来
读懂,再试着讲出来

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

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