举例说明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中的每个属性名,并将它们作为新类型的属性名。最后,TP得到了T中对应属性名的属性值类型,并将它们作为新类型的属性值类型。

相关推荐
mldong3 小时前
推荐一款支持AI的数据可视化一站式报表平台
前端·人工智能
风骏时光牛马3 小时前
AI开源工具一站式体验:上手探索原生AI能力
前端
鬼手点金11 小时前
nanoGPT/nanochat 能做出 DeepSeek/Qwen 这样的大模型吗?
服务器·前端·javascript·bug·openclaw
软件技术NINI11 小时前
美妆商城html+Css+js 4页
javascript·css·html
蛋蛋的就会顺顺的11 小时前
hot100 p0——栈,贪心算法,动态规划
java·前端·javascript·算法·leetcode·力扣
程序员Sunday12 小时前
TypeScript 的 any、unknown、never 有什么区别?
前端·面试·typescript
朱涛的自习室12 小时前
70 美金的 Beyond Compare,我让 Gemini 4 和 DeepSeek 造个开源免费版(Day 2)
android·前端·人工智能
码艺-Alimjan12 小时前
Tauri 源码备份 · 打包 & 解压 总结,源码收集之路
前端·javascript·vue.js
小马不起床12 小时前
零基础玩转 FastAPI_11:前端后台管理页面
前端·状态模式·fastapi
子非鱼a14 小时前
【文件上传】一个普普通通的edu16
前端