TypeScript 之 映射类型(重映射)

825 阅读4分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第19天,点击查看活动详情

前言

在 TypeScript 中,我们经常能看到 映射类型 的身影,比如在一些最常用的工具类型当中,举一个简单的 Partial 的例子,这个工具类型能够把一个对象类型的属性全都转化为可选。

type Person1 = {
  name:string
  age:number
}

type Person2 = Partial<Person1>

// type A2 = {
//     name?: string | undefined;
//     age?: number | undefined;
// }

这个有什么用呢,比如说第一个对象是我们使用的一个用户对象,在某些时候,比如说修改个人信息的场景下,我们就可以支持部分修改,那么这个对象中的属性就不是都必填的,在或者在查看信息页面,用户对象的属性用都要变成只读的,当然这也能够用映射类型来实现。

映射类型的基本概念

语法

在我们学每一种代码的某一个知识点的时候,首先要去了解的肯定都是它的语法,那么来看看映射类型的语法:

{ [ P in K ] : T }

概念

  1. 映射类型的本质是对象类型

  2. 映射类型,它又可以是一种泛型类型,可用于把原有的对象类型映射成新的对象类型。

首先从语法两边的大括号就能看出来映射类型它是一种对象类型,但是泛型类型并不是一定的,主要是他的意义决定了它得是一个泛型类型,比如说你想要将一个对象的属性全部变为可选,那就需要传入原有对象才可以进行新的映射,不如映射类型就没有意义了。所以我们说它是一种泛型类型也并没有错,只是不能够限死了映射类型中一定得有泛型语法。

type Person3 = {
  [P in 'name'|'age'] : string
}

// type Person3 = {
//     name: string;
//     age: string;
// }

上面这个 Person3 的类型中,并没有使用泛型语法,但是它是一个映射类型吗,是的,这样也算是一个映射类型,只是缺少了泛型的加入,我们就没有办法重用这个映射类型,那么它也就丧失了最初的帮我们复用代码的目的。

泛型类型

上面一直提到了泛型语法,那么,什么样的一个类型会被称为泛型呢

只要使用了泛型语法的,就是一个泛型,语法:

< T >

只要使用了上面这种泛型语法的类型,就算是一种泛型类型。

重映射

什么是重映射

TypeScript 4.1 版本允许我们使用 as 子句对映射类型中的键进行重新映射。它的语法如下:

type MappedTypeWithNewKeys<T> = {  
    [K in keyof T as NewKeyType]: T[K]
}

其中 NewKeyType 的类型必须是 string | number | symbol 联合类型的子类型。

按照我们正常的映射逻辑来说,映射过后的键值一定都是传入的 K 这个联合类型的每一项,但是使用 as 子句进行重映射可以让我们改变这个当前的键值。

举例

下面这个例子中,我们可以把传入的key值全部改为我们想要的key值

Pasted image 20220424111302.png

并且,结合 TypeScript 中的模板字符串的语法,我们就能够实现更加强大的重映射

type changeToFn<T> = {
  [K in keyof T as `get${string & K}`]: () => T[K]
};

type Person4 = {
    Name: string;
    [1]: number;
    age: number;
}

type personFn = changeToFn<Person4>;

// type personFn = {
//     getName: () => string;
//     getage: () => number;
// }

向上面这样,我们能够更改一个对象中的键名,使得它变为另外一种含义。

重映射的剥离作用

我们还可以使用重映射来剥离我们不想要的键值,比如说在某一个场景,是不需要年龄的,这个时候,我们就可以使用重映射来映射我们之前的 Person 对象,来构造一个不包含age的类型。

type Person4 = {
    Name: string;
    [1]: number;
    age: number;
}

type RemoveKey<T,K> = {
    [P in keyof T as Exclude<P, K>]: T[P]
};

type Person5 = RemoveKey<Person4,'age'>;

// type Person5 = {
//     Name: string;
//     1: number;
// }

这样我们能够通过泛型来传入指定的对象和需要移出的key值,来实现删除掉一些我们不想要的属性。

总结

本文更加深入的介绍了映射类型,以及映射类型的重映射相关知识,重映射在我们平时的使用当中是一个非常重要的功能,它使得映射类型变得更加的强大,以及能够应用到更多的场景当中去。