ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

The Concise TypeScript Book 精讲:Intersection Types(交叉类型)从定义到实战

The Concise TypeScript Book 精讲:Intersection Types(交叉类型)从定义到实战 文档教程【免费下载链接】typescript-bookThe Concise TypeScript Book: A Concise Guide to Effective Development in TypeScript. Free and Open Source.项目地址https://gitcode.com/gh_mirrors/typ/typescript-book点击查看免费下载本文是开源项目 The Concise TypeScript Book 第 33 章「Intersection Types」的深度精讲。你将掌握交叉类型的定义与语法理解它与 Union Type、interface 扩展的关系并学会在实际代码中用它组合对象、构造含歧义字段的复合类型与 Mixin 模式。所有示例均与仓库中 英文原版章节 及 韩文译版 一一对应可直接复制运行。一、什么是交叉类型定义与核心语法交叉类型Intersection Type是一种表示「同时拥有两个或多个类型全部属性」的值类型即最终类型的值必须满足被组合的每一个类型的全部约束。TypeScript 使用符号将多个类型连接起来type X { a: string; }; type Y { b: string; }; type J X Y; // Intersection const j: J { a: a, b: b, };type X、type Y各自定义一个只有单一属性的对象类型type J X Y声明了一个交叉类型J类型的值必须同时包含a: string与b: string两个属性因此变量j在赋值时必须同时给出a和b缺一不可否则 TypeScript 编译期就会报错。交叉类型的核心含义是「且」一个值要想属于X Y它就必须既属于X又属于Y。这与数学中的集合交集intersection恰好相反——类型作为「值的集合」时参见 探索类型系统 一章中 Types as Sets 的集合论视角X Y描述的是两个集合成员的并集属性而不是取两个值域的交集。这正是初学者最容易困惑的地方交叉类型组合的是类型的成员约束而非值集合的公共部分。与并集类型Union Type的对比交叉类型常与并集类型Union Type对照学习。并集类型用|表示「或」关系值可以是其中任意一个类型let x: string | number; x hello; // Valid x 123; // Valid两者的区分要点维度交叉类型并集类型|语义且必须满足所有类型约束或满足其中任意一个即可属性效果合并所有类型的属性叠加保留各成员类型使用时需收窄典型场景组合多个对象/接口的结构表示「多选一」的值域在 Type Manipulation 一章中两者被并列为「从已有类型创建新类型」的两种基本手段用于把多个类型合并为一个|用于定义一个可以是若干类型之一的新类型。二者是 TypeScript 类型组合的两大基石。二、交叉类型的本质为什么它是「结构叠加」交叉类型之所以能组合出同时包含全部属性的类型根源于 TypeScript 的结构类型系统Structural Typing。在 Erased Structural Types 一章中明确指出TypeScript 的对象类型并不要求与某个精确类型一一对应只要一个对象满足某接口的全部要求它就可以被用在需要该接口的任何位置——即便两者之间没有显式关联。这一特性让交叉类型在实际代码中表现得非常宽容且强大type A { foo: number }; type B { bar: string }; type C A B; const obj: C { foo: 42, bar: hello }; // 必须同时提供两个属性只要对象字面量同时具备foo与bar两个属性它就满足A B的全部约束无需任何继承或显式声明关系。也正是因为结构类型在编译后被完全擦除erased交叉类型不会产生任何运行时开销它只是编译期用于校验类型约束的一种静态构造。将交叉类型拆开使用交叉类型本身是一个类型别名type alias因此可以把它继续当作普通类型使用——把它作为函数参数类型、变量类型或继续与其他类型交叉type Name { name: string }; type Age { age: number }; type Person Name Age; // 等价于 { name: string; age: number } function greet(p: Person): string { return ${p.name} is ${p.age} years old; } const p: Person { name: Simon, age: 17 }; greet(p); // Simon is 17 years old三、与 interface 扩展extends的关系交叉类型和interface的extends是两种实现「类型组合」的路径但存在明显的能力差异。仓库 Extending Types 一章给出了权威对照interface 可以继承复制其他类型的成员interface X { a: string; } interface Y extends X { b: string; }interface 还可以同时继承多个类型interface A { a: string; } interface B { b: string; } interface Y extends A, B { y: string; }关键结论该章明确给出extends关键字只对 interface 和 class 生效对 type 别名组合的方式就是交叉类型type A { a: number; }; type B { b: number; }; type C A B;可以用 interface 继承 type但不能反过来type 没有extends能力type A { a: string; }; interface B extends A { b: string; }因此当你想组合两个type别名时是唯一选择而 Differences between Type and Interface 一章进一步补充了二者在扩展语义上的差别interface 使用extends关键字继承其他 interface 的属性和方法但interface 无法扩展诸如联合类型这样的复杂类型交叉类型则通过运算符把多个类型合并为一个能力更自由interface A { x: string; y: number; } type B A { j: string; }; const c: B { x: x, y: 123, j: j, };在「组合/交叉能力」上type显然比interface更灵活type可以随意使用组合任意类型包括联合类型、字面量类型、甚至其他交叉类型而 interface 的扩展对象被限定为可被extends的结构。这也是 Interface and Type 一章所总结的type 关键字在定义 Union 和 Intersection 类型时更为灵活。四、实战场景一组合零散的对象类型交叉类型最常见的用途是把分散定义的对象结构合并成一个完整结构。例如从基础信息与岗位信息组合出员工信息type Department dep-x | dep-y; // Union type Person { name: string; age: number; }; type Employee { id: number; department: Department; }; type EmployeeInfo Person Employee; // Intersection const info: EmployeeInfo { name: John, age: 30, id: 1001, department: dep-x, };这里EmployeeInfo Person Employee将「人的属性」与「员工属性」合并为一个包含 4 个属性的类型。该示例取自 Differences between Type and Interface 一章的 Union and Intersection Types 小节它同时展示了交叉类型可以与联合类型协同工作department字段本身是一个联合类型而EmployeeInfo是包含该联合类型的交叉类型。与索引类型、映射类型协同交叉类型也可以与其他类型操纵手段组合。例如与keyof索引访问配合type Person { name: string; age: number; email: string; }; // 取两个键构造「必填 可选」的复合配置类型 type RequiredKeys name | age; type PartialRest OmitPerson, RequiredKeys; type UpdatePayload PickPerson, RequiredKeys PartialPartialRest; const payload: UpdatePayload { name: Simon, age: 17, // email 可选 };这说明不只是简单拼接它可以与 Type Manipulation 中的Pick、Partial、Omit等内置工具类型自由嵌套构造出精准的业务类型。五、实战场景二混合同名字段类型交集语义当一个交叉类型中两个成员具有相同名称但不同类型的属性时结果属性类型是两个成员类型的交叉交集。以string与number为例type A { x: string }; type B { x: number }; type C A B; // x 的类型是 string number由于string number没有值能同时满足既要是 string 又要是 number该类型实际上等价于never。这意味着直接赋值{ x: a }或{ x: 1 }都会产生编译错误该属性在类型层面被「压成」不可能存在的值属于需要刻意避免的歧义设计。这一行为是集合论语义的直接体现属性类型的交集在两个不相交的集合上为空。设计类型时应尽量避免交叉成员的属性名冲突若确实需要可将冲突字段抽离或用Omit先剔除再交叉type A { id: string; name: string }; type B { id: number; createdAt: Date }; // 先剔除冲突字段 id再合并 type C OmitA, id B; // { name: string; id: number; createdAt: Date }与 Mixin 模式的联系交叉类型的这一「叠加」能力正是 TypeScript Mixin混入模式的基石。仓库 Others 一章的 Mixin classes 一节即基于交叉类型实现将多个类的实例结构交叉组合让一个类同时具备多种能力是函数式组合与类型系统的经典结合点也呼应了 Extending Types 中「type 用交叉类型扩展」的结论。六、编译期行为与注意事项交叉类型在运行时不存在交叉类型与并集类型一样是纯编译期的静态类型构造。TypeScript 在编译时会将这些类型别名擦除JavaScript 运行时不包含任何或类型标注痕迹因此交叉类型不会带来任何运行时性能开销交叉类型不会自动生成合并后的对象或类仍需在赋值时显式提供全部属性类型别名包括交叉类型不支持声明合并declaration merging而 interface 支持同名多次声明自动合并这是 Differences between Type and Interface 一章反复强调的差异。与never、unknown的交互结合 探索类型系统 的集合论表格never是空集never T等价于never空集与任何集合相交仍为空unknown是全集unknown T等价于T全集与任何集合相交为该集合本身any是每个集合的超集any T的结果在多数情况下会被简化为any。理解这层集合语义有助于预测交叉类型在边界情况下的行为避免写出意外的类型结果。保持可读性的建议交叉类型组合的成员越多结构越难以阅读建议为每个成员取语义化名称如type Person Name Age Contact优先复用具名 type/interface避免大段匿名对象直接参与当组合对象出现同名字段时显式使用Omit处理冲突保留类型的可预期性。七、小结要点结论定义表示同时拥有多个类型全部属性的值用连接各类型与并集对比是「且」叠加属性|是「或」多选一与 interface 扩展extends只能用于 interface/classtype 组合必须用interface 可继承 type反之不行同名字段属性类型取交集不相交时退化为never运行时编译期擦除零运行时开销不可声明合并典型应用组合对象类型、构造复合配置、Mixin 混入模式交叉类型是 TypeScript 类型系统的核心组合能力之一。掌握的语义并结合 Union Type、Extending Types、Differences between Type and Interface 以及 Type Manipulation 等章节对照学习你就能在 The Concise TypeScript Book 的完整脉络中把类型组合技巧熟练运用于真实项目。相关源码与示例均可直接在仓库website/src/content/docs/book/与website/src/content/docs/ko-kr/book/目录下查看与验证。赞分享文档教程【免费下载链接】typescript-bookThe Concise TypeScript Book: A Concise Guide to Effective Development in TypeScript. Free and Open Source.项目地址https://gitcode.com/gh_mirrors/typ/typescript-book点击查看免费下载相关推荐The Concise TypeScript Book 精讲Intersection Types交叉类型——用 将多个类型组合为一个类型The Concise TypeScript Book 精讲Intersection Types交叉类型——用 将多个类型组合为一个类型 交叉类型I文档教程The Concise TypeScript Book 精讲对象类型Object Types从定义到组合实战The Concise TypeScript Book 精讲对象类型Object Types从定义到组合实战 导读 对象类型是 TypeScript 类型文档教程The Concise TypeScript Book深入解析交叉类型Intersection Types与 运算符The Concise TypeScript Book深入解析交叉类型Intersection Types与 运算符 导读 交叉类型Intersec文档教程上一篇Flask-MongoEngine与WTForms集成快速创建MongoDB模型表单的完整指南下一篇告别扫码失败ZXing如何智能修复倾斜二维码创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进