Best ways to use "Extract" utility type in Typescript

Arafat - Apr 12 '23 - - Dev Community

Extract is a utitly type in Typescript that allows you to create a new type by extracting a subset of an existing type.

This article is inspired from this article from Matt Pocock.

Here are few possible ways to use Extract in Typescript:

Table of contents

Get a member of an union

We can extract a member of union by using Extract. The first argument is the full union, and the second argument is the member of the union that we want to get.

type Animal = "cat" | "dog" | "bird" | "fish";

type OnlyCat = Extract<Animal, "cat">; // 'cat'
Enter fullscreen mode Exit fullscreen mode

Get multiple members from an union

We can even get mulitple members from an union by using Extract. Here is how:

type Animal = "cat" | "dog" | "bird" | "fish";

type ExtractType = Extract<Animal, "cat" | "dog">; // 'cat' | 'dog
Enter fullscreen mode Exit fullscreen mode

Even if we pass a value to Extract that doesn't exist in the union, Typescript will return the values that exists in the union.

type Animal = "cat" | "dog" | "bird" | "fish";

type ExtractType = Extract<Animal, "cat" | "dog" | "tiger">; // 'cat' | 'dog'
Enter fullscreen mode Exit fullscreen mode

Get a member of a discriminated union

type Shape =
  | {
      type: 'square'
    }
  | {
      type: 'circle'
    }
  | {
      type: 'triangle'
    }
Enter fullscreen mode Exit fullscreen mode

A discriminated union type is one where each member has a discriminant property. The discriminant property is a common property that can be used to discriminate between the other members. In the example above, the type property is used to discriminate between the different shapes.

We can extract a member of the discriminated union by using Extract like this:

type SqaureShape = Extract<Shape, {type: 'square'}> // { type: 'square' }
Enter fullscreen mode Exit fullscreen mode

Get multiple members of a discriminated union

We can also extract multiple members of a discriminated union:

type SqaureAndCircleShape = Extract<Shape, {type: 'square'} | {type: 'circle'}> 
// { type: 'square' } | { type: 'circle' }
Enter fullscreen mode Exit fullscreen mode

This works even if the union members have other properties attached to them.

type Shape =
  | {
      type: 'square';
      size: number;
    }
  | {
      type: 'circle'
    }
  | {
      type: 'triangle'
    }

type SqaureAndCircleShape = Extract<Shape, {type: 'square'} | {type: 'circle'}> 
// {type: 'square'; size: number;} | { type: 'circle' }
Enter fullscreen mode Exit fullscreen mode

You can also get multiple members of the discriminated union by passing a union to the type property:

type Shape =
  | {
      type: 'square';
      size: number;
    }
  | {
      type: 'circle'
    }
  | {
      type: 'triangle'
    }

type SqaureAndCircleShape = Extract<Shape, {type: 'square' | 'circle'}> 
// {type: 'square'; size: number;} | { type: 'circle' }
Enter fullscreen mode Exit fullscreen mode

Get members of a discriminated union by shape

type Routes =
  | {
      route: '/user'
      search: {
        id: string
      }
    }
  | {
      route: '/user/create'
    }
  | {
      route: '/user/edit'
      search: {
        id: string
      }
    }

type RoutesWithSearch = Extract<
  Routes,
  {
    search: any
  }
>
/* 
{
    route: '/user';
    search: {
        id: string;
    };
} | {
    route: '/user/edit';
    search: {
        id: string;
    };
}
*/
Enter fullscreen mode Exit fullscreen mode

To get the members of union you don't need to always include the discriminator (in this case, route) in the second argument. You can just pass the shape of the members you want to get.

In this case, we want to extract the types from the Routes union type that have a search property.


Get members by a type

type allTypes = 'admin' | 'user' | 5 | 6 | 7 | true

type onlyNumbers = Extract<allTypes, number> // 5 | 6 | 7
Enter fullscreen mode Exit fullscreen mode

In the example above, we remove all literals that don't match the number type from the allTypes union. Hence, we are only getting the numbers.


Get strings containing a substring from an union

type keys = 'userId' | 'tweetId' | 'userName' | 'tweetName'

type UserKey = Extract<keys, `${'user'}${string}`> // "userId" | "userName"
Enter fullscreen mode Exit fullscreen mode

The resulting UserKey type will be a union of the string literals from strings that start with the string "user." This case will include only the userId and userName string literals.


Get strings with one of several possible values from an union

type keys = 'userId' | 'tweetId' | 'id' | 'userName' | 'friendName'

type OnlyIdKey = Extract<keys, `${string}${'id' | 'Id'}${string}`> 
// "userId" | "tweetId" | "id"
Enter fullscreen mode Exit fullscreen mode

You can also use Extract to get all strings from a union that contain one of several possible substrings.

In this case, the resulting OnlyIdKey type will be a union of the string literals from keys containing the id or Id. This case will include the userId, tweetId, and id string literals.



Conclusion

So that's it, guys. I hope you found the article helpful. Extract is a utility type that can be used in many ways. If you think there are more ways to use Extract, please let me know in the comments. Thanks for reading the article. I will see you all in my next article🐸.

Visit:
👨‍💻My Portfolio
🏞️My Fiverr

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .