javascript技巧

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript技巧 > TypeScript 交叉类型

TypeScript 交叉类型的实现

作者:小赵同学WoW

本文主要介绍了TypeScript 交叉类型的实现,用通俗例子讲清它和联合类型的区别、对象属性如何合并、同名属性冲突为何变成never,以及如何用它扩展类型和组合职责,帮你快速掌握这个核心概念

摘要

本文介绍 TypeScript 交叉类型 & 的含义与使用方式,说明对象属性组合、同名属性冲突与 never 的形成,并对比联合类型,梳理类型扩展和职责组合等常见场景。

1. 什么是交叉类型

交叉类型使用 & 连接多个类型,表示一个值需要同时满足所有类型。

type A = { a: string };
type B = { b: number };
type C = A & B;

C 类型的值既要满足 A,也要满足 B:

const value: C = {
  a: 'hello',
  b: 100,
}; // ✅

可以把 A & B 读成:

既是 A,又是 B。

2. 对象交叉

交叉类型最常见的用途,是组合多个对象类型。

type Student = {
  name: string;
  score: number;
};

type Teacher = {
  name: string;
  age: number;
  subject: string;
};

type User = Student & Teacher;

User 必须拥有两边要求的全部属性:

const user: User = {
  name: '小王',
  score: 95,
  age: 30,
  subject: '数学',
}; // ✅

少了任何必选属性都不可以:

const user: User = {
  name: '小王',
  age: 30,
  subject: '数学',
}; // ❌ 缺少 Student 要求的 score

一句话记忆:

对象交叉不是二选一,而是把两边的要求都加到同一个值上。

3. 为什么叫“交叉”,结果却像属性合并

刚开始学习时,很容易认为两个对象的“交集”应该只留下公共属性。这是把属性集合类型的值集合混在了一起。

type A = { name: string; score: number };
type B = { name: string; age: number };
type C = A & B;

A & B 表示:寻找既能赋值给 A,又能赋值给 B 的值。

要同时满足这两个类型,对象就必须拥有:

所以结果看起来像属性合并:

const person: C = {
  name: '小明',
  score: 90,
  age: 18,
};

这里取的是“同时属于 A 类型和 B 类型的值”,不是取“A 和 B 的公共属性”。

4. 同名属性如何处理

4.1 同名属性类型相同

如果两边存在同名属性,并且属性类型相同,那么该属性正常合并:

type A = {
  name: string;
  score: number;
};

type B = {
  name: string;
  age: number;
};

type C = A & B;

name 同时满足两边的 string,因此仍然是 string

const person: C = {
  name: '小明',
  score: 90,
  age: 18,
}; // ✅

4.2 同名属性类型有重合

同名属性本身也会进行交叉:

type A = {
  id: string;
};

type B = {
  id: string | number;
};

type C = A & B;

id 既要是 string,又要是 string | number,所以最终只能是 string

const value: C = {
  id: 'abc',
}; // ✅

4.3 同名属性类型完全冲突

如果同名属性的类型完全没有重合,属性会变成 never

type A = {
  id: string;
};

type B = {
  id: number;
};

type C = A & B;

此时 C['id'] 相当于:

type Id = string & number; // never

不存在一个普通值能同时是 stringnumber,因此无法正常创建 C 类型的对象:

const value: C = {
  id: 'abc', // ❌ string 不能赋值给 never
};

5. 基础类型的交叉

交叉类型不只是简单地把内容放在一起,而是寻找同时满足两边条件的值。

没有重合部分

type Result = string & number; // never

一个值不可能既是字符串又是数字,所以结果是 never

type Color = 'red' & 'blue'; // never

一个值也不可能同时是 'red''blue'

有重合部分

type Result = (string | number) & string;

string | numberstring 都允许的值只有字符串,所以结果是:

type Result = string;

再看一个字面量例子:

type Color = ('red' | 'blue') & 'red';
// 结果是 'red'

6. 交叉类型和联合类型的区别

type A = {
  name: string;
};

type B = {
  age: number;
};

联合类型A | B

表示满足其中至少一个类型即可:

const value1: A | B = { name: '小明' };         // ✅
const value2: A | B = { age: 18 };              // ✅
const value3: A | B = { name: '小明', age: 18 }; // ✅

交叉类型A & B

表示必须同时满足两个类型:

const value1: A & B = { name: '小明' };          // ❌ 缺少 age
const value2: A & B = { age: 18 };               // ❌ 缺少 name
const value3: A & B = { name: '小明', age: 18 }; // ✅
类型含义赋值要求使用属性
`AB`A 或 B至少完整满足一个未收窄时只能使用公共属性
A & BA 且 B同时完整满足所有类型可以使用两边的属性

记忆:

7. 实际用途

7.1 在已有类型上增加属性

type Goods = {
  id: number;
  name: string;
  price: number;
};

type CartItem = Goods & {
  count: number;
};

type OrderItem = Goods & {
  count: number;
  totalPrice: number;
};

创建购物车商品时,既要提供商品信息,也要提供数量:

const cartItem: CartItem = {
  id: 1,
  name: '苹果',
  price: 5,
  count: 2,
};

创建订单商品时,需要满足更多要求:

const orderItem: OrderItem = {
  id: 1,
  name: '苹果',
  price: 5,
  count: 2,
  totalPrice: 10,
};

这种写法可以复用已有类型,达到类似“扩展类型”的效果。

7.2 组合不同职责的数据

type User = {
  id: number;
  name: string;
};

type Timestamp = {
  createdAt: Date;
  updatedAt: Date;
};

type UserRecord = User & Timestamp;

UserRecord 同时包含用户信息和时间信息:

const user: UserRecord = {
  id: 1,
  name: '小明',
  createdAt: new Date(),
  updatedAt: new Date(),
};

8. 结构类型带来的赋值现象

TypeScript 主要根据对象的结构判断能否赋值。属性更多的对象,可以赋值给只要求其中一部分属性的类型。

const cartItem: CartItem = {
  id: 1,
  name: '苹果',
  price: 5,
  count: 2,
};

const goods: Goods = cartItem; // ✅ cartItem 拥有 Goods 要求的全部属性

反过来不可以:

const goods: Goods = {
  id: 1,
  name: '苹果',
  price: 5,
};

const cartItem: CartItem = goods; // ❌ goods 缺少 count

判断时不要只看类型名称,要看这个值是否具备目标类型要求的全部结构。

9. 总结

  1. 交叉类型使用 &,表示一个值必须同时满足所有类型。
  2. 对象交叉后,需要提供各个对象类型要求的全部必选属性。
  3. 同名属性也要同时满足两边的类型要求。
  4. 同名属性完全冲突时,该属性会变成 never,通常导致对象无法创建。
  5. A | B 是满足至少一个,A & B 是同时满足全部。
  6. 交叉类型常用于复用已有对象类型,并在其基础上增加新属性。

最重要的一句话:

联合类型是在多个可能中选一个;交叉类型是把多个要求同时加到一个值上。

到此这篇关于TypeScript 交叉类型的实现的文章就介绍到这了,更多相关TypeScript 交叉类型内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文