Logo
Section 1 / 11

定义与用法

在本节课中,我们将为接下来关于映射类型的课程打下基础。

导入

定义与用法

在本节课中,我们将为接下来关于映射类型的课程打下基础。

什么是映射类型?

映射类型允许我们基于现有类型创建新的类型。这里的“映射”指的是通过自定义逻辑,将原有类型的成员指向一种新类型,这种逻辑由映射器的实现方式决定。

一个典型的例子是:保留原有接口的所有成员,但将其全部变为可选(optional)或只读(read-only)。

映射类型的优点

第一个优点

映射类型相较于早期不支持它的 TypeScript 版本具有两大优势。

在映射类型出现之前,我们需要额外创建一个接口来反映期望的最终状态。这会污染代码库,因为根据接口转换的方式不同,可能需要为每个不同的目标接口创建多个重复的接口定义。

此外,每当原始接口发生变化时,所有相关的接口都必须手动同步更新。这种维护成本迅速变得难以管理。

下面的代码展示了在映射类型引入前,如何使用两个接口来实现一个可变对象和一个不可变对象。这是没有映射类型时的常见做法:

1interface OriginalInterface { 2 x: number; 3 y: string; 4} 5 6interface ReadOnlyOriginalInterface { 7 readonly x: number; 8 readonly y: string; 9} 10 11let variable1: OriginalInterface = { x: 1, y: "2" }; 12let variable2: ReadOnlyOriginalInterface = { x: 1, y: "2" }; 13variable1.x = 2; // 可以修改值 14// variable2.x = 2; // 无法修改值

第二个优点

第二个优点是:在没有映射类型的情况下,每种接口都需要编写独立的转换函数。这种方式很快就会失控。

而有了映射类型后,我们只需要一个通用的转换函数,并定义出对应的映射类型即可。借助泛型,这个转换函数可以完全自洽——它接收一个泛型接口作为输入,返回一个映射后的类型定义,而该定义本身也使用了泛型。

我们将在后续课程中深入讲解泛型的概念。目前,我们可以简单理解为:泛型提供了一种可复用的方式来改变接口的类型结构。

下面的代码展示了一个简单的函数,用于将一个接口转换为另一个类型:

1// 定义一个允许重新赋值的接口结构 2interface OriginalInterface { 3 x: number; 4 y: string; 5} 6 7// 定义一个仅在创建时允许赋值的接口结构 8interface ReadOnlyOriginalInterface { 9 readonly x: number; 10 readonly y: string; 11} 12 13let variable1: OriginalInterface = { x: 1, y: "2" }; 14let variable2: ReadOnlyOriginalInterface = { x: 1, y: "2" }; 15 16// 一个将对象转换为只读类型的函数 17function mapOriginalInterfaceToBeReadOnly(o: OriginalInterface): ReadOnlyOriginalInterface { 18 return o; 19} 20 21let variable3 = mapOriginalInterfaceToBeReadOnly(variable1); 22// variable3.x = 2;

在接下来的课程中,我们将看到更实际的应用场景,展示映射类型如何减少为每种类型都编写转换函数的负担。本节中的代码并未使用映射类型,要将一个对象转换为另一种接口,必须复制接口并为每个字段添加 readonly,同时还要编写对应的转换函数。


让我们在下一课中学习更优的解决方案。

函数

使用 Readonly 实现不可变数据