Appshref
Programming / Software / AI
Published on: Feb 5, 2025, in

Understanding the Extract Utility Type in TypeScript

Understanding the Extract Utility Type in TypeScript

Introduction

TypeScript provides several built-in utility types that help developers work with complex types more effectively. One such utility is Extract, which allows you to filter specific types from a union type. This article will provide a detailed explanation of:

  • The syntax and signature of Extract
  • How Extract works
  • Use cases where Extract is useful
  • Tips and tricks for using Extract effectively

By the end of this article, you’ll have a solid understanding of the Extract utility type and how to use it efficiently in TypeScript.


Syntax and Signature of Extract

The Extract utility type is defined as follows:

Extract<T, U>;

Parameters:

  1. T – The union type from which to extract certain types.
  2. U – The subset of types to extract from T.

The Extract type will return a new type containing only the elements of T that are assignable to U.

Example:

type Status = "success" | "error" | "pending";
type SuccessStatus = Extract<Status, "success">;
// SuccessStatus = "success"

In this example, Extract<Status, "success"> returns only the "success" type from the Status union.


How Extract Works

The Extract utility works by filtering types from T that are assignable to U. If a type in T matches U, it is kept; otherwise, it is excluded.

Example:

type Event = "click" | "hover" | "keydown" | "keyup";
type KeyboardEvent = Extract<Event, "keydown" | "keyup">;
// KeyboardEvent = "keydown" | "keyup"

Here, Extract<Event, "keydown" | "keyup"> results in a type containing only "keydown" | "keyup", since these are the only members of Event that match U.

Internally, Extract<T, U> is implemented using conditional types:

type Extract<T, U> = T extends U ? T : never;

For each type T, if it extends U, it is included; otherwise, it is replaced with never, effectively removing it from the result.


Use Cases of Extract

1. Filtering Specific Values from a Union Type

The most common use case of Extract is filtering out specific types from a union. For example:

type Role = "admin" | "user" | "guest";
type AdminRole = Extract<Role, "admin">;
// AdminRole = "admin"

This allows us to extract only the "admin" type from the union.

2. Narrowing Event Types in TypeScript

When working with event listeners, Extract can help narrow down event types.

type EventType = "click" | "focus" | "scroll" | "keydown";
type UIEventType = Extract<EventType, "click" | "focus" | "scroll">;
// UIEventType = "click" | "focus" | "scroll"

This ensures that UIEventType only contains UI-related events.

3. Extracting Types from Interfaces

You can use Extract to filter keys from a set of keys.

interface Person {
  id: number;
  name: string;
  age: number;
  isAdmin: boolean;
}

type StringKeys = Extract<keyof Person, string>;
// StringKeys = "name"

This extracts only the string keys from the Person interface.

4. Filtering Function Return Types

Extract can be used to filter function return types.

type ResponseType = "success" | "error" | 200 | 400;
type StatusCodes = Extract<ResponseType, number>;
// StatusCodes = 200 | 400

This extracts only the numeric values from ResponseType.


Tips and Tricks for Using Extract

1. Using Extract with Generics

You can use Extract in generic functions to enforce type safety dynamically.

function getStatus<T extends string>(status: Extract<"success" | "error" | "pending", T>) {
  return `The status is ${status}`;
}

console.log(getStatus("success"));
// Valid
// console.log(getStatus("failure")); // Error: Argument of type '"failure"' is not assignable

This ensures that only valid statuses are accepted as arguments.

2. Using Extract with Conditional Types

You can combine Extract with other conditional types for more complex filtering.

type Primitive = string | number | boolean | object;
type OnlyStrings = Extract<Primitive, string>;
// OnlyStrings = string

This ensures that only string is extracted from the union.

3. Combining Extract with Exclude

You can use Exclude along with Extract to create more refined types.

type Data = "name" | "age" | "address";
type SelectedData = Extract<Data, "name" | "age">;
type RemainingData = Exclude<Data, SelectedData>;
// RemainingData = "address"

This ensures that RemainingData contains values not included in SelectedData.

4. Extracting Numeric Types from Mixed Unions

If you have a mixed union of types and need only numeric values, Extract can help.

type MixedTypes = "hello" | 42 | true | 100;
type NumbersOnly = Extract<MixedTypes, number>;
// NumbersOnly = 42 | 100

This efficiently extracts only numbers from the mixed union.


Conclusion

The Extract utility type in TypeScript is a powerful tool for filtering and narrowing down types in a type-safe manner. It helps in refining union types, narrowing event types, extracting interface keys, and more.

Key Takeaways:

  • Extract<T, U> filters types from T that match U.
  • Useful for refining event types, extracting interface keys, and enforcing function argument constraints.
  • Can be combined with other utility types like Exclude for more flexibility.
  • Helps in preventing type errors and improving type safety.