【TypeScript】映射类型详解

TypeScript 是一种强类型的 JavaScript 超集,允许开发者在构建大型应用时获得更好的类型安全。本文将详细介绍 TypeScript 中的映射类型及其应用,通过映射类型,开发者可以基于现有类型创建新的类型,从而避免重复代码,提高可维护性。

一、映射类型概述

1. 什么是映射类型

映射类型是一种基于现有类型生成新类型的机制。它的语法基于索引签名,允许开发者动态地为类型的属性定义新的类型。通过映射类型,可以轻松地将一种类型的属性转换为另一种类型的属性,避免手动逐个定义。

2. 映射类型的基本语法

映射类型的基本语法如下:

type MappedType<OriginalType> = {
    
    
  [Property in keyof OriginalType]: NewType;
};

在这个语法中,OriginalType 是要映射的原始类型,Property 是其属性,NewType 是新属性的类型。下面是一个简单的例子:

type OnlyBoolsAndHorses = {
    
    
  [key: string]: boolean | Horse;
};

在这个例子中,OnlyBoolsAndHorses 是一个映射类型,表示所有字符串键的值可以是布尔值或 Horse 类型。

二、映射类型的应用实例

1. 基于已有类型创建新类型

通过映射类型,我们可以轻松地将已有类型的属性转换为其他类型。以下示例展示了如何将一个对象类型的所有属性转换为布尔值:

type OptionsFlags<Type> = {
    
    
  [Property in keyof Type]: boolean;
};

type Features = {
    
    
  darkMode: () => void;
  newUserProfile: () => void;
};

type FeatureOptions = OptionsFlags<Features>;
// 结果:
// type FeatureOptions = {
    
    
//     darkMode: boolean;
//     newUserProfile: boolean;
// }

在这个例子中,OptionsFlagsFeatures 类型的所有属性的类型更改为布尔值。

2. 修改映射属性的可变性和可选性

TypeScript 中的映射类型还允许我们使用修饰符来控制属性的可变性和可选性。常用的修饰符包括 readonly?,可以通过前缀 -+ 来移除或添加这些修饰符。

例子:移除 readonly
type CreateMutable<Type> = {
    
    
  -readonly [Property in keyof Type]: Type[Property];
};

type LockedAccount = {
    
    
  readonly id: string;
  readonly name: string;
};

type UnlockedAccount = CreateMutable<LockedAccount>;
// 结果:
// type UnlockedAccount = {
    
    
//     id: string;
//     name: string;
// }
例子:移除可选属性
type Concrete<Type> = {
    
    
  [Property in keyof Type]-?: Type[Property];
};

type MaybeUser = {
    
    
  id: string;
  name?: string;
  age?: number;
};

type User = Concrete<MaybeUser>;
// 结果:
// type User = {
    
    
//     id: string;
//     name: string;
//     age: number;
// }

三、键重映射

TypeScript 4.1 及以上版本允许通过 as 子句在映射类型中进行键重映射,这使得我们可以根据需要重新定义属性名称。

使用 as 进行键重映射

type Getters<Type> = {
    
    
  [Property in keyof Type as `get${
      
      Capitalize<string & Property>}`]: () => Type[Property];
};

interface Person {
    
    
  name: string;
  age: number;
  location: string;
}

type LazyPerson = Getters<Person>;
// 结果:
// type LazyPerson = {
    
    
//     getName: () => string;
//     getAge: () => number;
//     getLocation: () => string;
// }

在这个例子中,我们通过模板字面量类型为 Person 的属性生成了新的 getter 函数。

四、过滤属性

映射类型还可以结合条件类型来过滤掉某些属性,创造出新的类型。

移除特定属性

以下示例展示了如何移除对象中的某个属性:

type RemoveKindField<Type> = {
    
    
  [Property in keyof Type as Exclude<Property, "kind">]: Type[Property];
};

interface Circle {
    
    
  kind: "circle";
  radius: number;
}

type KindlessCircle = RemoveKindField<Circle>;
// 结果:
// type KindlessCircle = {
    
    
//     radius: number;
// }

在这个例子中,我们使用 Exclude 来过滤掉 kind 属性。

五、对任意联合类型的映射

映射类型不仅限于字符串、数字或符号的联合类型,还可以对任何类型的联合进行映射。

映射任意事件配置

type EventConfig<Events extends {
     
      kind: string }> = {
    
    
  [E in Events as E["kind"]]: (event: E) => void;
};

type SquareEvent = {
    
     kind: "square"; x: number; y: number };
type CircleEvent = {
    
     kind: "circle"; radius: number };

type Config = EventConfig<SquareEvent | CircleEvent>;
// 结果:
// type Config = {
    
    
//     square: (event: SquareEvent) => void;
//     circle: (event: CircleEvent) => void;
// }

在这个例子中,EventConfig 将不同类型的事件映射为函数。

六、进一步探索映射类型

映射类型与 TypeScript 的其他特性结合良好。以下示例展示了一个使用条件类型的映射类型,根据对象的某个属性生成新的布尔值:

提取 PII(个人身份信息)

type ExtractPII<Type> = {
    
    
  [Property in keyof Type]: Type[Property] extends {
    
     pii: true } ? true : false;
};

type DBFields = {
    
    
  id: {
    
     format: "incrementing" };
  name: {
    
     type: string; pii: true };
};

type ObjectsNeedingGDPRDeletion = ExtractPII<DBFields>;
// 结果:
// type ObjectsNeedingGDPRDeletion = {
    
    
//     id: false;
//     name: true;
// }

在这个例子中,我们提取了标记为 PII 的字段,返回一个布尔值表示是否需要删除。

七、总结

TypeScript 中的映射类型提供了一种强大且灵活的方式来创建新类型。通过映射类型,开发者可以高效地基于现有类型构建新的类型,避免重复代码,提升代码的可维护性。希望本文能帮助你更好地理解映射类型的用法,并在实际项目中充分发挥其潜力,从而提升开发效率和代码质量。

推荐:


在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/lph159/article/details/143461448