举例说明typescript的Exclude、Omit、Pick

一、提前知识说明:联合类型

typescript的联合类型是一种用于表示一个值可以是多种类型中的一种的类型。我们使用竖线(|)来分隔每个类型,所以number | string | boolean是一个可以是number,string或boolean的值的类型。

联合类型可以用于模拟一些值可能有重叠类型的情况。例如,假设我们有一个函数,它可以接受一个数字或一个字符串作为参数。我们可以使用联合类型来定义这个函数的参数类型:

复制代码
function print(value: number | string) {
    console.log(value);
}

print(1); // OK
print("hello"); // OK
print(true); // Error

如果我们有一个联合类型的值,我们只能访问所有类型共有的成员。https://www.typescriptlang.org/docs/handbook/unions-and-intersections.html?ref=hackernoon.com 例如,假设我们有一个Fish和Bird两个接口,它们都有layEggs方法,但只有Fish有swim方法,只有Bird有fly方法。我们可以定义一个返回Fish或Bird的函数:

复制代码
interface Fish {
    swim(): void;
    layEggs(): void;
}

interface Bird {
    fly(): void;
    layEggs(): void;
}

declare function getSmallPet(): Fish | Bird;

然后,我们可以调用这个函数,并访问返回值的layEggs方法,因为它是Fish和Bird共有的:

复制代码
let pet = getSmallPet();
pet.layEggs(); // OK

但是,我们不能访问返回值的swim或fly方法,因为它们不是Fish和Bird共有的:

复制代码
let pet = getSmallPet();
pet.swim(); // Error
pet.fly(); // Error

要想访问这些方法,我们需要使用类型断言或者类型守卫来缩小联合类型的范围。 例如:

复制代码
let pet = getSmallPet();

// 使用类型断言
if ((pet as Fish).swim) {
    (pet as Fish).swim();
} else if ((pet as Bird).fly) {
    (pet as Bird).fly();
}

// 使用类型守卫
function isFish(pet: Fish | Bird): pet is Fish {
    return (pet as Fish).swim !== undefined;
}

if (isFish(pet)) {
    pet.swim();
} else {
    pet.fly();
}

二、Exclude

typescript的Exclude是一个内置的工具类型,用于从一个联合类型中排除一些指定的类型,从而创建一个新的联合类型。https://www.typescriptlang.org/tsconfig/exclude.html 它的语法是:

复制代码
Exclude<Type, ExcludedUnion>

其中,Type是一个联合类型,ExcludedUnion是一个要排除的类型或者它们的联合类型,表示要从Type中排除的类型。

例如,假设我们有一个Shape类型,它定义了几种形状:

复制代码
type Shape = "circle" | "square" | "triangle" | "rectangle";

如果我们想要创建一个不包含circle和square的新类型,我们可以使用Exclude来实现:

复制代码
type ShapeWithoutCircleAndSquare = Exclude<Shape, "circle" | "square">;

这样,ShapeWithoutCircleAndSquare类型就相当于:

复制代码
type ShapeWithoutCircleAndSquare = "triangle" | "rectangle";

Exclude的实现原理是基于条件类型。条件类型可以根据一个条件表达式,选择两个可能的类型中的一个。Exclude的源码如下:

复制代码
type Exclude<T, U> = T extends U ? never : T;

这里,T是联合类型,U是要排除的类型。首先,T extends U检查了T是否可以赋值给U,如果可以,则返回never类型,表示排除掉T;如果不可以,则返回T本身,表示保留T。然后,这个条件类型会分布地应用到T中的每个成员上,并组合成一个新的联合类型。

三、Omit

typescript的Omit是一个内置的工具类型,用于从一个对象类型中排除一些指定的属性,从而创建一个新的对象类型。它的语法是:

Omit<Type, Keys>

其中,Type是一个对象类型,Keys是一个字符串字面量类型或者它们的联合类型,表示要从Type中排除的属性名。

例如,假设我们有一个User类型,它定义了用户的一些信息:

复制代码
type User = {
    name: string;
    age: number;
    email: string;
    address: string;
};

如果我们想要创建一个不包含email和address属性的新类型,我们可以使用Omit来实现:

复制代码
type UserWithoutEmailAndAddress = Omit<User, "email" | "address">;

这样,UserWithoutEmailAndAddress类型就相当于:

复制代码
type UserWithoutEmailAndAddress = {
    name: string;
    age: number;
};

Omit的实现原理是基于Pick和Exclude两个工具类型。Pick用于从一个对象类型中选择一些指定的属性,Exclude用于从一个联合类型中排除一些指定的类型。Omit的源码如下:

复制代码
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;

这里,T是对象类型,K是要排除的属性名。首先,keyof T得到T的所有属性名组成的联合类型,然后Exclude<keyof T, K>排除掉K中指定的属性名,得到剩余的属性名组成的联合类型。最后,Pick<T, Exclude<keyof T, K>>从T中选择剩余的属性名对应的属性,得到新的对象类型。

四、pick

typescript的Pick是一个内置的工具类型,用于从一个对象类型中选择一些指定的属性,从而创建一个新的对象类型。https://www.typescriptlang.org/docs/handbook/utility-types.html 它的语法是:

Pick<Type, Keys>

其中,Type是一个对象类型,Keys是一个字符串字面量类型或者它们的联合类型,表示要从Type中选择的属性名。https://www.typescriptlang.org/docs/handbook/utility-types.html

例如,假设我们有一个Todo类型,它定义了一个待办事项的信息:

复制代码
type Todo = {
    title: string;
    description: string;
    completed: boolean;
};

如果我们想要创建一个只包含title和completed属性的新类型,我们可以使用Pick来实现:

复制代码
type TodoPreview = Pick<Todo, "title" | "completed">;

这样,TodoPreview类型就相当于:

复制代码
type TodoPreview = {
    title: string;
    completed: boolean;
};

Pick的实现原理是基于映射类型。映射类型可以根据一个已有的类型,通过遍历它的属性,生成一个新的类型。https://ultimatecourses.com/blog/using-typescript-pick-mapped-type Pick的源码如下:

复制代码
type Pick<T, K extends keyof T> = {
    [P in K]: T[P];
};

这里,T是对象类型,K是要选择的属性名。首先,keyof T得到T的所有属性名组成的联合类型,然后K extends keyof T约束了K必须是T的属性名之一。接着,[P in K]遍历了K中的每个属性名,并将它们作为新类型的属性名。最后,T[P]得到了T中对应属性名的属性值类型,并将它们作为新类型的属性值类型。

相关推荐
李鸿耀15 分钟前
仅用几行 CSS,实现优雅的渐变边框效果
前端
码事漫谈35 分钟前
解决 Anki 启动器下载错误的完整指南
前端
im_AMBER1 小时前
Web 开发 27
前端·javascript·笔记·后端·学习·web
蓝胖子的多啦A梦1 小时前
低版本Chrome导致弹框无法滚动的解决方案
前端·css·html·chrome浏览器·版本不同造成问题·弹框页面无法滚动
玩代码1 小时前
vue项目安装chromedriver超时解决办法
前端·javascript·vue.js
訾博ZiBo2 小时前
React 状态管理中的循环更新陷阱与解决方案
前端
StarPrayers.2 小时前
旅行商问题(TSP)(2)(heuristics.py)(TSP 的两种贪心启发式算法实现)
前端·人工智能·python·算法·pycharm·启发式算法
一壶浊酒..2 小时前
ajax局部更新
前端·ajax·okhttp
苏打水com3 小时前
JavaScript 面试题标准答案模板(对应前文核心考点)
javascript·面试
Wx-bishekaifayuan3 小时前
基于微信小程序的社区图书共享平台设计与实现 计算机毕业设计源码44991
javascript·vue.js·windows·mysql·pycharm·tomcat·php