Exclude<UnionType, ExcludedMembers> Utility Types in TypeScript With Examples
What Is Exclude<UnionType, ExcludedMembers>
In this article, we will introduce and explore one such utility type: Exclude< UnionType, ExcludedMembers>. This utility type is particularly useful when working with complex type structures, as it enables developers to create a new type by excluding specific members from an existing union type.
Syntax
Here's the basic syntax for using Exclude<UnionType, ExcludedMembers>
type NewType = Exclude<UnionType, ExcludedMembers>;
For example, let's say you have a union type Animal
and you want to create a
new
type that excludes the 'Fish' member:
type Animal = "Dog" | "Cat" | "Fish";
type LandAnimal = Exclude<Animal, "Fish">;
In this case, the LandAnimal
type would be equivalent to the union
type 'Dog' | 'Cat'
, as the Fish
member has been excluded.
Time To Transition From JavaScript To TypeScript
Level Up Your TypeScript And Object Oriented Programming Skills. The only complete TypeScript course on the marketplace you building TypeScript apps like a PRO.
SEE COURSE DETAILSExample Use Case
In a real-world application, let's say we are building an e-commerce platform that sells various types of products. We have a union type Product representing all possible product types:
type Product = "Electronics" | "Clothing" | "Toys" | "Books" | "Furniture";
Now, we want to create a promotional campaign targeting only a subset of these
product types, excluding Electronics
and Furniture
. Using the
Exclude<UnionType, ExcludedMembers>
utility type, we can create a new type for
the
targeted product categories:
type TargetedProducts = Exclude<Product, "Electronics" | "Furniture">;
The TargetedProducts type will now represent the union
type 'Clothing' | 'Toys' | 'Books'
.
We can then define a function to apply a discount to the targeted product categories:
interface ProductItem {
type: Product;
price: number;
}
function isTargetedProduct(
productType: Product
): productType is TargetedProducts {
const targetedProducts: TargetedProducts[] = ["Clothing", "Toys", "Books"];
return targetedProducts.includes(productType as TargetedProducts);
}
function applyPromotion(product: ProductItem): ProductItem {
const discount = 0.1;
if (isTargetedProduct(product.type)) {
product.price -= product.price * discount;
}
return product;
}
In this example, we used the Exclude<UnionType, ExcludedMembers>
utility type
to
create the TargetedProducts
type, which represents the product categories
eligible for the promotional campaign. The applyPromotion
function applies a
discount to the product price if the product belongs to the targeted categories,
ensuring type safety through the use of the isTargetedProduct
type guard
function.
Combining With Other Utility Types
The power of utility types lies in their ability to be combined with other
utility types to create more complex types. In this example, we'll look at
the use of Exclude<UnionType, ExcludedMembers>
in conjunction with
the Partial<T>
utility type. Let's say we have an online project management application, and we
want to create a feature for updating a task. We have a Task
interface, which
represents the task object:
interface Task {
id: number;
title: string;
description: string;
status: "ToDo" | "InProgress" | "Completed";
}
Now, we want to create an UpdateTask
type to represent the task properties
that
can be updated, excluding 'id'
as it should remain constant. We can use the
Exclude utility type in combination with the keyof operator and the Partial
utility type:
type UpdatableKeys = Exclude<keyof Task, "id">;
type UpdateTask = Partial<Pick<Task, UpdatableKeys>>;
The UpdatableKeys
type represents all keys of the Task type excluding 'id'
,
and the UpdateTask
type represents a partial version of the Task
type that
includes only the updatable properties.
Now we can create a function to update a task with the new properties:
function updateTask(task: Task, updates: UpdateTask): Task {
const updatedTask: Task = { ...task, ...updates };
return updatedTask;
}
We used the Exclude<UnionType, ExcludedMembers>
utility type along with the
keyof operator and the Partial<T>
utility type to create a type for updating
tasks, ensuring that only the allowed properties can be updated while
maintaining type safety.
Conclusion
Utility types in TypeScript, when examined individually, may sometimes appear to have limited use or seem redundant. It's easy to overlook their potential in isolation; however, the true power of utility types emerges when they are combined to achieve advanced levels of type checking and manipulation, resulting in more expressive and type-safe code.
By leveraging the capabilities of different utility types together, you can create complex type structures and annotations that better represent the business logic and constraints of your application. This synergy between utility types enables you to harness the full power of TypeScript's type system, providing a more robust development experience.
What Can You Do Next 🙏😊
If you liked the article, consider subscribing to Cloudaffle, my YouTube Channel, where I keep posting in-depth tutorials and all edutainment stuff for software developers.