作为一名TypeScript开发者,我经常被问到很多关于TypeScript工具类型的问题——尤其是如何在应用程序代码中使用它们。所以,我开始了一个关于它们的系列——围绕现实世界的例子。
让我们从 Exclude
类型帮助器开始。
1. 移除联合的成员
type Fruit = "apple" | "banana" | "orange";
type Result = Exclude<Fruit, "orange">;
// type Result = "apple" | "banana"
可以使用 Exclude
删除联合的单个成员。第一个参数表示完整的联合,第二个参数表示要删除的成员。
从技术上讲,第二个参数可以是任何类型——如果你试图删除一个不存在的成员,TypeScript不会警告你。它只会返回原来的组合。
type Result = Exclude<Fruit, "pear">;
// type Result = "apple" | "banana" | "orange"
2. 从联合中删除多个成员
type Event = "click" | "focus" | "change" | "abort";
type ClickAndFocusEvent = Exclude<
Event,
"change" | "abort"
>;
还可以使用 Exclude
从联合中删除多个成员。通过将联合传递给第二个实参,可以一次删除多个成员。
如上所述,并非所有这些成员都需要存在于原始联合中:
type ClickAndFocusEvent = Exclude<
// type ClickAndFocusEvent = "click" | "focus"
Event,
"change" | "abort" | "blur"
>;
3. 移除区分联合的成员
type Event =
| {
type: "click";
}
| {
type: "focus";
}
| {
type: "change";
};
区分联合通常是对象之间的联合,这些对象具有可用于区分它们的共同属性。在上面的示例中, type
属性用于区分不同的事件。
通过使用 Exclude
删除所有没有 type
属性特定值的成员,可以提取联合的一个子集。
type Event =
| {
type: "click";
}
| {
type: "focus";
}
| {
type: "change";
};
type ClickAndFocusEvent = Exclude<
// type ClickAndFocusEvent = {
// type: "click";
// } | {
// type: "focus";
// }
Event,
{ type: "change" }
>;
即使联合的成员具有附加的其他属性,这也可以工作。
type Event =
| {
type: "click";
x: number;
y: number;
}
| {
type: "focus";
}
| {
type: "change";
value: string;
};
type ClickAndFocusEvent = Exclude<Event, { type: "click" }>;
// { type: 'focus' } | { type: 'change', value: string }
在上面的例子中,为了移除 click
事件,不需要将 x
和 y
属性传递给 Exclude
。
4.移除区分联合的多个成员
type Event =
| {
type: "click";
}
| {
type: "focus";
}
| {
type: "change";
}
| {
type: "abort";
};
type ClickAndFocusEvent = Exclude<
// type ClickAndFocusEvent = {
// type: "click";
// } | {
// type: "focus";
// }
Event,
{ type: "change" } | { type: "abort" }
>;
还可以通过将联合传递给第二个参数来删除有区分联合的多个成员。它可以是联合成员的并集,也可以是 type
属性的并集:
type ClickAndFocusEvent = Exclude<
Event,
{ type: "change" | "abort" }
>;
5. 通过形状排除区分联合的成员
type Routes =
| {
route: "/user";
search: {
id: string;
};
}
| {
route: "/user/create";
}
| {
route: "/user/edit";
search: {
id: string;
};
};
type RoutesWithoutSearch = Exclude<
// type RoutesWithoutSearch = {
// route: "/user/create";
// }
Routes,
{
search: any;
}
>;
您不需要在 Exclude
的第二个参数中包含'discriminator'(在本例中为 route
)。你可以只传递你想要移除的成员的形状。
在上面的例子中,我们删除了 Routes
联合中所有具有 search
属性的成员。
6. 从联合中删除所有字符串/数字/布尔值
type PossibleTypes = "admin" | "user" | 0 | 1 | 2;
type StringTypes = Exclude<PossibleTypes, number>;
// type StringTypes = "admin" | "user"
Exclude也适用于基本类型。在上面的例子中,我们从 PossibleTypes
联合中删除了所有匹配 number
的字面值。
如果您想要从联合中删除所有字符串、所有数字或所有布尔值,这将非常有用。
7. 从联合中删除包含子字符串的字符串
type ObjectKey =
| "userId"
| "postId"
| "userName"
| "postName";
type PostKey = Exclude<
// type PostKey = "postId" | "postName"
ObjectKey,
`${string}${"user"}${string}`
>;
可以使用 Exclude
从联合中删除包含特定子字符串的所有字符串。
在上面的例子中,我们从 ObjectKey
联合中删除了所有包含子字符串 user
的字符串。
我们使用模板字面值来表示要删除的字符串——在本例中为 user
。然后使用 ${string}
语法来表示出现在要删除的子字符串之前或之后的任何字符串。
8. 从联合中删除具有几个可能值之一的字符串
type ObjectKey =
| "userId"
| "postId"
| "id"
| "userName"
| "postName";
type NonIdKey = Exclude<
// type NonIdKey = "userName" | "postName"
ObjectKey,
`${string}${"id" | "Id"}${string}`
>;
还可以使用 Exclude
从联合中删除包含几个可能的子字符串之一的所有字符串。
在上面的例子中,我们从 ObjectKey
联合中删除了所有包含 id
或 Id
的字符串。通过向模板文本传递一个联合,我们可以一次删除多个子字符串。
9. 从联合中删除具有特定前缀/后缀的字符串
type ObjectKey =
| "userId"
| "postId"
| "id"
| "userName"
| "postName";
type NonNameKey = Exclude<ObjectKey, `${string}Name`>;
// type NonNameKey = "userId" | "postId" | "id"
您可以使用 Exclude
从联合中删除具有特定前缀或后缀的所有字符串。
在上面的例子中,我们从 ObjectKey
联合中删除了所有以 Name
结尾的字符串。
这里, ${string}
用于表示在要删除的子字符串之前出现的任意长度的字符串。
要将其转换为匹配某个前缀,可以将 ${string}
移到模板字面值的末尾。
我错过了什么?
Exclude
是一个非常强大的实用程序类型,可以以多种方式使用。如果你有其他使用 Exclude
的例子,请在文章下方留言告诉我!
欢迎关注公众号:文本魔术,了解更多