Sunday面试指南

TypeScript 联合类型和交叉类型有什么区别?类型收窄怎么做?

下面是一段教学用的模拟面试。

🧑‍💻 面试官:联合类型和交叉类型有什么区别?

🙋‍♂️ 我:联合类型表示其中一种,交叉类型表示同时满足。

🧑‍💻 面试官:请求结果可能成功,也可能失败,用交叉类型把两种字段合起来好吗?

🙋‍♂️ 我:应该用联合类型,再根据状态判断。

🧑‍💻 面试官:那进入 success 分支以后,TypeScript 为什么知道可以读取 data?如果两个交叉类型的同名字段冲突呢?

类型收窄的关键不是“强行转成想要的类型”,而是给出足以排除其他可能性的条件。

面试速答(60 秒版)

联合类型 A | B 表示值可以属于 A,也可以属于 B。使用它时,要先处理不同可能性,或者通过判断把类型范围缩小。

交叉类型 A & B 则要求同时满足两边的约束,适合把共同需要的能力组合起来,但不是简单地把所有字段无条件拼在一起。

比如接口结果有成功和失败两种状态,可以让它们分别带上不同的 status 字面量。判断 status 以后,TypeScript 就能知道当前是哪一种结果,这叫可辨识联合的收窄。

实际开发时,我会尽量让类型反映真实状态,避免“所有字段都可选”。类型断言只是告诉编译器怎么理解,不能替代运行时检查。交叉类型的字段如果相互矛盾,还可能出现 never。

可能一种,和同时满足

图:可能一种,和同时满足。

知识点详解:让类型表达真正可能出现的状态

为什么所有字段都可选,会让代码更难写?

假设请求结果包含 status、data 和 error。把 data、error 都写成可选,看起来兼容所有情况,却也允许“成功没有数据”“失败没有错误”“两者同时出现”这些本来不希望出现的组合。

联合类型可以分别声明成功结果和失败结果。这样,每一种状态都具备自己必须拥有的字段。

TypeScript

type Result =
  | { status: "success"; data: string[] }
  | { status: "error"; error: string };

function message(result: Result): string {
  if (result.status === "success") {
    return result.data.join(",");
  }
  return result.error;
}

本题讨论 TypeScript 静态类型机制,Python 没有相同的编译器和语法规则,因此不提供机械翻译版本。

联合类型为什么不能随便访问某一边的字段?

函数参数是 A | B,说明调用方可能给 A,也可能给 B。没有更多条件时,函数必须兼容两种输入,因此只能安全使用共同可用的操作。

判断 status 等于 success 后,其他分支被排除,data 就成为当前分支的有效字段。这不是编译器凭空猜测,而是依据可辨识字段与控制流程做分析,见 类型收窄文档。

typeof、in、instanceof 也可以提供不同层面的证据。但要注意自己的业务边界:如果输入来自网络,首先仍要确认它确实符合声明的结构。

检查状态,排除其他可能

图:检查状态,排除其他可能。

交叉类型为什么可能产生 never?

假设一边要求 id 是 string,另一边要求 id 是 number。交叉类型要求同一个 id 同时满足两种约束,但没有普通值能同时属于这两种基本类型,因此这个属性会落入 never。

所以,交叉不是把冲突字段“后者覆盖前者”。它表达的是同时满足。组合对象能力时,应确认这些约束能够共存,具体例子见 对象类型文档。

例如同时要求某个对象有 name 和 createdAt,就可以组合两种独立约束;但若两个状态互斥,就不应该用交叉来合并。

收窄和断言,有什么本质区别?

收窄依据代码中的判断,比如检查 status,逐步排除其他可能。断言则是开发者直接告诉编译器“当它是这个类型”。

如果实际数据不符合断言,运行时不会因为写了 as 而自动修正。自定义类型谓词也一样:它是我们写给编译器的承诺,函数内部检查是否充分,需要自己保证。

新增一种请求状态时,还可以利用穷尽检查,让未处理分支在编译期暴露。不要为了消除报错,把剩余情况统一断言成已经处理过的类型。

面试官继续追问

A | B 是把字段合在一起吗?

不是。它表示可能是 A,也可能是 B。能直接使用哪些字段,取决于在当前分支是否对所有可能都安全。

用 if (result.data) 就足够了吗?

不一定。空字符串、零或其他合法值可能被当成假;字段本身也未必是稳定的判别条件。明确的 status 字面量通常更容易表达业务状态。

类型检查能判断服务端真的返回了什么吗?

不能。它检查的是代码中的类型关系。网络输入仍然需要运行时验证,验证后再进入已知类型的业务处理。

面试速记卡

  • 联合:可能属于其中一种。
  • 交叉:同时满足两边约束,不是冲突字段覆盖。
  • 可辨识联合:用状态字面量表达互斥分支。
  • 收窄:依靠判断排除其他可能性。
  • 断言:不执行校验,不修正真实数据。

公司面试真题

这道题暂未收录可核验的公司真题来源。你可以先阅读本文解析,或浏览已收录的公司面试真题。

浏览公司面试真题 →
简历汪永久免费在线制作简历,模板直接套用、导出无水印,永久免费、下载免费,不需要付费解锁任何功能。去写简历