耀极客论坛

 找回密码
 立即注册
查看: 609|回复: 0

TypeScript 映射类型详情

[复制链接]

193

主题

176

帖子

276

积分

中级会员

Rank: 3Rank: 3

积分
276
发表于 2022-5-9 01:51:02 | 显示全部楼层 |阅读模式
  这篇文章主要介绍了TypeScript 映射类型详情,一个类型需要基于另外一个类型, 又不想拷贝一份,这个时候可以考虑使用映射类型,映射类型建立在索引签名的语法上,下面文章我们就从回顾下索引签名展开TypeScript 映射类型的相关资料,需要的朋友可以参考一下
  前言:
  TypeScript 的官方文档早已更新,但我能找到的中文文档都还停留在比较老的版本。所以对其中新增以及修订较多的一些章节进行了翻译整理。
  本篇翻译整理自 TypeScript Handbook 中 「Mapped Types」 章节。
  本文并不严格按照原文翻译,对部分内容也做了解释补充。

1.映射类型(Mapped Types)

  有的时候,一个类型需要基于另外一个类型,但是你又不想拷贝一份,这个时候可以考虑使用映射类型。
  映射类型建立在索引签名的语法上,我们先回顾下索引签名:
  1. // 当你需要提前声明属性的类型时
  2. type OnlyBoolsAndHorses = {
  3.   [key: string]: boolean | Horse;
  4. };
  5. const conforms: OnlyBoolsAndHorses = {
  6.   del: true,
  7.   rodney: false,
  8. };
复制代码
  而映射类型,就是使用了 PropertyKeys 联合类型的泛型,其中 PropertyKeys 多是通过 keyof 创建,然后循环遍历键名创建一个类型:
  1. type OptionsFlags‹Type> = {
  2.   [Property in keyof Type]: boolean;
  3. };
复制代码
  在这个例子中,OptionsFlags 会遍历 Type 所有的属性,然后设置为布尔类型。
  1. type FeatureFlags = {
  2.   darkMode: () => void;
  3.   newUserProfile: () => void;
  4. };
  5. type FeatureOptions = OptionsFlags‹FeatureFlags>;
  6. // type FeatureOptions = {
  7. //    darkMode: boolean;
  8. //    newUserProfile: boolean;
  9. // }
复制代码
2.映射修饰符(Mapping Modifiers)

  在使用映射类型时,有两个额外的修饰符可能会用到,一个是 readonly,用于设置属性只读,一个是 ? ,用于设置属性可选。
  你可以通过前缀 - 或者 + 删除或者添加这些修饰符,如果没有写前缀,相当于使用了 + 前缀。
  1. // 删除属性中的只读属性
  2. type CreateMutable‹Type> = {
  3.   -readonly [Property in keyof Type]: Type[Property];
  4. };
  5. type LockedAccount = {
  6.   readonly id: string;
  7.   readonly name: string;
  8. };
  9. type UnlockedAccount = CreateMutable‹LockedAccount>;
  10. // type UnlockedAccount = {
  11. //    id: string;
  12. //    name: string;
  13. // }
  14. // 删除属性中的可选属性
  15. type Concrete‹Type> = {
  16.   [Property in keyof Type]-?: Type[Property];
  17. };
  18. type MaybeUser = {
  19.   id: string;
  20.   name?: string;
  21.   age?: number;
  22. };
  23. type User = Concrete‹MaybeUser>;
  24. // type User = {
  25. //    id: string;
  26. //    name: string;
  27. //    age: number;
  28. // }
复制代码
3.通过 as 实现键名重新映射(Key Remapping via as)

  在 TypeScript 4.1 及以后,你可以在映射类型中使用 as 语句实现键名重新映射:
  1. type MappedTypeWithNewProperties‹Type> = {
  2.     [Properties in keyof Type as NewKeyType]: Type[Properties]
  3. }
复制代码
  举个例子,你可以利用「模板字面量类型」,基于之前的属性名创建一个新属性名:
  1. type Getters‹Type> = {
  2.     [Property in keyof Type as `get${Capitalize‹string & Property>}`]: () => Type[Property]
  3. };
  4. interface Person {
  5.     name: string;
  6.     age: number;
  7.     location: string;
  8. }
  9. type LazyPerson = Getters‹Person>;
  10. // type LazyPerson = {
  11. //    getName: () => string;
  12. //    getAge: () => number;
  13. //    getLocation: () => string;
  14. // }
复制代码
  你也可以利用条件类型返回一个 never 从而过滤掉某些属性:
  1. // Remove the 'kind' property
  2. type RemoveKindField‹Type> = {
  3.     [Property in keyof Type as Exclude‹Property, "kind">]: Type[Property]
  4. };
  5. interface Circle {
  6.     kind: "circle";
  7.     radius: number;
  8. }
  9. type KindlessCircle = RemoveKindField‹Circle>;
  10. // type KindlessCircle = {
  11. //    radius: number;
  12. // }
复制代码
  你还可以遍历任何联合类型,不仅仅是 string | number | symbol 这种联合类型,可以是任何类型的联合:
  1. type EventConfig‹Events extends { kind: string }> = {
  2.     [E in Events as E["kind"]]: (event: E) => void;
  3. }
  4. type SquareEvent = { kind: "square", x: number, y: number };
  5. type CircleEvent = { kind: "circle", radius: number };
  6. type Config = EventConfig‹SquareEvent | CircleEvent>
  7. // type Config = {
  8. //    square: (event: SquareEvent) => void;
  9. //    circle: (event: CircleEvent) => void;
  10. // }
复制代码
4.深入探索(Further Exploration)

  映射类型也可以跟其他的功能搭配使用,举个例子,这是一个使用条件类型的映射类型,会根据对象是否有 pii 属性返回 true 或者 false :
  1. type ExtractPII‹Type> = {
  2.   [Property in keyof Type]: Type[Property] extends { pii: true } ? true : false;
  3. };
  4. type DBFields = {
  5.   id: { format: "incrementing" };
  6.   name: { type: string; pii: true };
  7. };
  8. type ObjectsNeedingGDPRDeletion = ExtractPII‹DBFields>;
  9. // type ObjectsNeedingGDPRDeletion = {
  10. //    id: false;
  11. //    name: true;
  12. // }
复制代码

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|耀极客论坛 ( 粤ICP备2022052845号-2 )|网站地图

GMT+8, 2022-12-10 04:15 , Processed in 0.065285 second(s), 20 queries .

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表