ts中这些实用的工具类型,你还不会?

1,079 阅读7分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第 7 天,点击查看活动详情

大家好,我是爱吃鱼的桶哥Z,ts(TypeScript)出来这么久了,相信大家或多或少在自己接触的项目中都有用到吧,虽然我们平时的开发中都有用到ts,但是ts还有很多内置的工具类型方法估计很多人都没有实际使用过,今天我们就一起来探讨一下ts这些内置的工具类型函数吧!

Partial<Type>

主要用于构造类型Type,并将它所有的属性设置为可选的。它的返回类型表示输入类型的所有子类型。光看这个描述,估计大部分人都还不知道这个工具类型到底有什么用,那么我们就一起再代码中来实践一下吧!

interface StateTypes {
    name: string;
    age: number;
}

/*
 * 更新用户信息
 * @param user 对象类型 StateTypes
 * @param filterUserInfo 过滤类型
 * @return object 过滤后的用户信息
 */
const updateUserInfo = (user: StateTypes, updateData: Partial<StateTypes>) => {
    return { ...user, ...updateData }
};

// 测试
const user1: StateTypes = {
    name: 'zhangsan',
    age: 18
};

const user2 = updateUserInfo(user1, {
    age: 22
});

console.log(user2); // { name: 'zhangsan', age: 22 }

上面的例子看起来很简单,那么在实际的开发中,我们一般会怎么使用Partial<Type>这个工具类型呢?举一个实际开发中的例子,代码如下:

// 例如:我们跟后端进行数据的交互时,某些字段不是必填的,我们就可以用Partial来进行处理
interface SendDataProps {
    name: string;
    age: number;
    username: string;
    password: string;
    phone: number;
    sex: boolean;
}

const sendData: Partial<SendDataProps> = {
    name: 'zhangsan',
    age: 18,
    username: 'zhangsan',
    password: '123123',
    phone: 13012341234
};

如果用户不愿意选择自己的性别,那么就可以通过Partial将这些数据都变成可选的,大家都知道在开发中如果我们要让某个参数设置为可选,一般都是在参数名后面加,但是有了Partial后,我们就不需要自动显示的去添加了,那么这个方法你学会了吗?

Required<Type>

既然Partial<Type>是将对象中所有的参数都设为可选的,那么自然也有将对象中所有参数设为必填的方法,它就是Required<Type>,通过字面量的意思我们都能明白这个方法的含义,它与Partial<Type>是相对的,因此我们可以将这两个方法一起进行记忆和学习,能够加强对它们的理解。

下面我们一起来看一下Required<Type>的例子,代码如下:

interface StateProps {
    name: string;
    age?: number;
}

const user1: StateProps = { name: 'zhangsan' };

const user2: Required<StateProps> = { name: 'lisi' }; // 这里就会报错了,因此Required将所有参数都改为必填的

在实际开发中,我们的用途主要是用于约束相关字段必填,具体的例子我们还是拿上面Partial中使用到的来举例:

// 虽然我们定义用户的性别在前端界面是可选的,但是后端需要将这个字段保存到数据库中
interface SendDataProps {
    name: string;
    age: number;
    username: string;
    password: string;
    phone: number;
    sex?: boolean;
}

const sendData: Required<SendDataProps> = {
    name: 'zhangsan',
    age: 18,
    username: 'zhangsan',
    password: '123123',
    phone: 13012341234,
    sex: 0,  // 这里我们默认给一个0,表示性别未知
}

当我们使用Required<Type>来限制前端传递给后端的数据时,ts就会帮我们检测我们传递的时是否都必填了,如果没有填写就会给出相应的提示,这样就可以避免因为上线后产生的各种问题。

Readonly<Type>

顾名思义,这个方法主要用于将对象总所有的属性设置为readonly(仅读),也就是说构造出的类型的属性不能被再次赋值。下面一起来看一下官方的例子:

interface StateProps {
    name: string;
    age: number;
}

const userInfo: Readonly<StateProps> = {
    name: 'zhangsan',
    age: 18
};

// 当修改 userInfo.name 时,则会报错
userInfo.name = 'lisi'; // Error: cannot reassign a readonly property

这个方法就比较简单了,就是用于限制对象中的字段只读属性的,虽然我们用const定义的这个对象是常量,但是const如果定义的是一个对象,里面的属性其实还是可以修改的,而使用了Readonly<Type>后,则更进一步限制了const定义的对象,大家可以自己试一试就明白其中的道理了。

Record<Keys, Type>

这个方法应该是目前使用的最多的一个方法了,它的基本意思是:构造一个类型,其属性名的类型为K,属性值的类型为T。这个工具可用来将某个类型的属性映射到另一个类型上。看到这个解释是不是有点懵?别急,我们一起来看一下例子就能明白它的含义了,例子如下:

interface UserProps {
    name: string;
    age: number;
}

type SexType = 'man' | 'woman' | 'other';

const user: Record<SexType, UserProps> = {
    man: { name: 'hanlei', age: 18 },
    woman: { name: 'limeimei', age: 17 },
    other: { name: 'xxx', age: 2 }
};

Record<Type>这个方法简单来说,第一个参数其实就是定义对象的Key类型,第二个参数定义的是对象的Value类型,而我们一般在实际的开发中如果不确定某个对象里面有什么值,但是我们知道它是个object,我们就可以这么来用:

const sendData: Record<string, any> = {
    name: 'zhang',
    age: 18
};

我们定义某个对象,却不知道里面的值有哪些的时候,用Record就很方便了,我们只需要知道它的Keystring类型,而Value类型我们就不用在意了。当然这样的使用方式其实也不太推荐,毕竟不知道具体的Value有哪些值对于我们的操作来说还是有很大的限制和不确定性在里面。

Pick<Type, Keys>

官方的解释意思为:从类型Type中挑选部分属性Keys来构造新的类型。看这个描述还是有点懵,我们还是一起来看代码吧,代码如下:

interface StateProps {
    name: string;
    age: number;
    sex: boolean;
}

type UserType = Pick<StateProps, 'name' | 'age'>;

const user: UserType = {
    name: 'zhangsan',
    age: 18
};

上面的代码一面了然,简单来说就是将前面对象中的Key取出来,组成一个新的对象,我们依旧可以拿前面的例子来具体,代码如下:

interface SendDataProps {
    name: string;
    age: number;
    username: string;
    password: string;
    phone: number;
}

type OtherProps = 'name' | 'age' | 'username' | 'phone';

const sendData: Pick<SendDataPropsOtherProps> = request.data;  // 伪代码,从服务端获取到的数据

sendData.name;
sendData.phone;

当我们从后端那边获取到数据,我们并不需要将所有的数据都展示出来时,就可以用Pick来过滤成一个新的对象,里面只有我们需要的字段即可。

Omit<Type, Keys>

上面的Pick是从对象中挑选部分属性来组成新的类型,而Omit则是从类型Type中获取所有属性,然后从中剔除Keys属性后构造一个新的类型。我们依旧来看例子就能理解了,代码如下:

interface StateProps {
    name: string;
    age: number;
    sex: boolean;
}

type UserType = Omit<StateProps, 'sex'>;

const user: UserType = {
    name: 'zhangsan',
    age: 18
};

其实PickOmit能够实现的效果都差不多,只是它们两个一个是从一堆内容中挑选值,另外一个是从一堆内容中删除某个值。

最后

ts中还为我们提供了一下实用的工具类型,相对来说今天介绍的这几种在平常的开发中会用的比较多,后续还有一些其它的工具类型我们后面再来一起学习吧。要理解这些工具类型的定义以及它们的使用场景,这需要大量的在开发中进行实践,光看不练是没用的,所以我们一起加油吧,ts的未来一片光明,我们千万不要掉队了!

最后,如果这篇文章有帮助到你,❤️关注+点赞❤️鼓励一下作者,谢谢大家

参考文档

Utility Types

实用工具类型

TypeScript Utility Types