Skip to main content

Extract<Type, Union> Utility Types in TypeScript With Examples

What Is Extract<Type, Union>

The Extract<Type, Union> utility type in TypeScript is a powerful and convenient feature that allows developers to create new types by extracting specific types from a union type. This utility type can be particularly useful when you want to narrow down a larger union type to a more specific subset, making it easier to work with and understand.

Syntax

Here's what the basic syntax looks like:

type NewType = Extract<Type, Union>;
  • Type: This is the type you want to extract from the union. It can be a single type or a union type itself. The Type is compared with each member of the Union to determine which types to extract.

Union: This is the union type from which you want to extract the specific types. It consists of two or more types combined with the | (pipe) symbol.

To demonstrate the syntax, let's consider a simple example:

type Animal = "Dog" | "Cat" | "Fish" | "Bird";
type Pet = Extract<Animal, "Dog" | "Cat">; // Result: "Dog" | "Cat"

In this example, we have an Animal union type containing four different types of animals. Using the Extract utility type, we can create a new Pet type containing only the animals that match our criteria (in this case, "Dog" and "Cat").

TypeScript Course Instructor Image
TypeScript Course Instructor Image

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 DETAILS

Application Example

Let's consider a task management system where users can create and manage different types of tasks, such as "Meeting", "Deadline", "Reminder", and " Event". We want to implement a function that filters out only the "Meeting" and "Deadline" tasks to display on a specific view. Using the Extract<Type, Union> utility type, we can achieve this easily and in a type-safe manner.

First, let's define our union type TaskType and the Task interface:

type TaskType = "Meeting" | "Deadline" | "Reminder" | "Event";

interface Task {
id: number;
title: string;
type: TaskType;
date: Date;
}

Now, we'll create a type alias RelevantTaskType using the Extract utility type to include only "Meeting" and "Deadline" task types:

type RelevantTaskTypes = Extract<TaskType, "Meeting" | "Deadline">;
// Result: "Meeting" | "Deadline"

Next, we implement the function filterRelevantTasks that takes an array of tasks and returns only those with types matching the RelevantTaskTypes:

function filterRelevantTasks(tasks: Task[]): Task[] {
return tasks.filter(
(task) => task.type === "Meeting" || task.type === "Deadline"
);
}

Finally, let's create an array of tasks and use the filterRelevantTasks function:

const tasks: Task[] = [
{ id: 1, title: "Team Meeting", type: "Meeting", date: new Date() },
{ id: 2, title: "Project Deadline", type: "Deadline", date: new Date() },
{ id: 3, title: "Doctor's Appointment", type: "Reminder", date: new Date() },
{ id: 4, title: "Conference", type: "Event", date: new Date() },
];

const relevantTasks = filterRelevantTasks(tasks);
console.log(relevantTasks);

The filterRelevantTasks function will return an array containing only the "Meeting" and "Deadline" tasks, as specified by the RelevantTaskTypes type alias.

Combining Extract With Other Utility Types

In this example, we will combine the Extract<Type, Union> utility type with the Partial<Type> utility type in TypeScript. The Partial<Type> utility type creates a new type with all properties of the given Type set as optional. In the process we are also going to use mapped types as well as Record type.

Let's assume we have a Person type and a Student type, both having a common property, age. We want to extract the common properties and create a new type with those properties set as optional.

First, define the Person and Student types:

type Person = {
name: string;
age: number;
address: string;
};

type Student = {
age: number;
grade: number;
};

Next, we'll create a union type PersonAndStudent to combine both types:

type PersonAndStudent = Person | Student;

Now, let's use the Extract<Type, Union> utility type to get the common properties, age in this case:

type CommonProperties = {
[K in keyof PersonAndStudent]: (Person[K] extends PersonAndStudent[K]
? K
: never) &
(Student[K] extends PersonAndStudent[K] ? K : never);
}[keyof PersonAndStudent];

The CommonProperties type will result in the union type "age".

Finally, we'll use the Partial<Type> utility type to create a new type with the extracted common property set as optional:

type PartialCommonProperties = Partial<Record<CommonProperties, number>>;

The PartialCommonProperties type will be:

// {
// age?: number;
// }

Conclusion

By comparing the given Type with each member of the Union, the Extract utility type forms a new union type containing only the matching types. This versatile feature can be applied in various scenarios, such as filtering out certain types or refining function argument types, contributing to a more robust and type-safe codebase.

Furthermore, the Extract<Type, Union> utility type can be combined with other utility types, such as Partial<Type>, to create even more tailored and powerful types.

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.

YouTube @cloudaffle