前端进阶之旅前端进阶之旅
  • 基础篇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 条件类型 extends 三元表达式
TyTypeScript类型运算

TypeScript 条件类型怎么写,和 JavaScript 三元表达式有什么区别?

外形像三元表达式,判断的却是类型关系,产出的也是类型。

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

把类型问题写成可检查的分支

  1. 检查对象当前工具接受的类型参数及其结构
  2. 关系判断是否满足目标类型的可赋值要求
  3. 结果选择分别返回满足与不满足条件时的类型

与联合、any 或 never 配合时还有额外规则,不能把所有输入都按单个普通对象简单推理。

核心回答

先记住这个答案

条件类型通常写成 T extends U ? X : Y,含义是根据 T 对 U 的可赋值性关系选择类型结果。它不是执行某个 JavaScript 布尔表达式,也不会在运行时创建分支或改变数据。把结构判断放在条件内部,可以让工具接受更广输入,在满足条件时提取字段,不满足时返回明确的失败类型;这与直接要求泛型参数必须满足约束不同。泛型尚未确定时,结果可能暂时无法归约,函数体里的普通判断也不保证自动证明所有复杂条件返回关系。

  • extends 在此判断类型关系而非运行时继承
  • 条件分支的结果是类型,不生成数据变换
  • 内部条件允许处理不满足结构的输入类型

为什么条件内部可以读取专有字段

工具想获取对象的 message 字段类型,但输入也可能没有该字段。先在条件中检查结构,成功分支就能在这份证据下进行索引访问;失败分支返回 never,表示当前输入没有对应结果。这样不必把所有调用者都限制为带 message 的对象。

示例对不同结构计算不同结果,字符串消息得到字符串类型,数字消息得到数字类型,没有字段则得到 never。接收字符串消息类型的变量不能赋数字,说明条件选择仍然产生正常静态约束,并没有让类型系统变成任意通过的描述。

按结构决定字段类型是否存在TypeScript
type MessageOf<T> = T extends { message: unknown } ? T['message'] : never;
type TextMessage = MessageOf<{ message: string; code: number }>;
type NumericMessage = MessageOf<{ message: number }>;
type MissingMessage = MessageOf<{ code: number }>;
const text: TextMessage = 'ready';
// @ts-expect-error TextMessage 是 string
const invalid: TextMessage = 7;

三个别名分别归约为 string、number 和 never。这里没有任何运行时对象解析过程,数字赋给文本类型的预期错误只验证静态结果,不能证明外部响应已经带有正确字段。

与外层泛型约束有什么不同

如果直接写 T extends { message: unknown } 作为类型参数约束,不含字段的输入在使用工具时就会被拒绝。把判断放进条件类型,则可以接受这个输入,并把失败解释为 never 或其他约定结果。两者对应不同接口设计:禁止输入与计算失败结果。

失败类型也应有明确含义。随意使用 any 会让后续失去检查,使用 never 则可能在更大联合运算中被消去。需要保留失败原因时,可以返回带标签的类型结构。应根据工具如何被组合选择结果,不能只以哪种写法最短为准。

类型分支不能替代程序分支

JavaScript 三元表达式根据实际值选择并计算某一边,条件类型在编译后消失。把接口响应套进条件类型,不会自动检查字段、转换字符串或选择运行处理器。程序仍需要真实的条件、解析和错误路径,类型工具只是帮助描述这些行为。

当返回类型依赖尚未确定的泛型参数时,函数实现可能无法用简单 if 自动证明条件返回正确。遇到这种情况,应检查是否更适合重载、明确的结果联合或更简单签名,不要直接对每个返回值断言来遮住无法证明的关系。

回答前,多想一步

容易答错的地方

条件类型会在浏览器中执行三元判断
它只参与类型计算,生成的 JavaScript 不包含对应验证代码;需要根据实际输入选择行为时,仍要写真实运行时判断。
extends 总是在要求类继承关系
条件类型中的 extends 主要表达可赋值性判断,普通结构类型也可以参与;应根据语法位置区分泛型约束、条件判断和类继承。
试着用自己的话回答

面试官还会怎么问?

失败分支为什么经常返回 never?

它可以表达没有匹配类型,并在后续联合运算中自然被消去;如果调用者需要区分失败原因,应设计更显式的结果类型。

把输入设成联合时会逐个判断吗?

某些写法会触发分发,尤其是检查位置为裸类型参数时;这是一项独立规则,应确认是逐成员处理还是希望把整个联合一起比较。

条件类型能直接判断某个变量当前值吗?

它处理静态类型信息,无法读取任意运行时值;保留字面量的变量可以提供更具体类型,但动态输入仍需要实际检查和解析。

从一道题,走向一组知识

把知识连起来

类型运算

TypeScript 条件类型为什么对联合分发,方括号怎样让它整体判断?

联合输入需要明确是否按成员分发条件计算

泛型设计

TypeScript 的 T extends Shape 约束了什么,为什么不能直接把 Shape 返回成 T?

区分限制合法输入与在类型内部选择失败分支

参考资料

  • TypeScript:Conditional Types

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

本题目录
  1. 先记住这个答案
  2. 为什么条件内部可以读取专有字段
  3. 与外层泛型约束有什么不同
  4. 类型分支不能替代程序分支
  5. 容易答错的地方
  6. 面试官还会怎么问
  7. 把知识连起来
读懂,再试着讲出来

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

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