DEV Community

Arthur Vincent Simon
Arthur Vincent Simon

Posted on

Typescript Utility Types

Introduction

As I was starting to get serious in learning Typescript, I came across a set of utility types the proved useful when I tried to refactor the types in the codebase of the company that we are in.

Before that point, I assumed that for reusing types code, I have to make granular types and export them to each type that need them in their fields.

For example, if I have a Person type that I am using in a Parent type or a Child type, I have to create it, export it out and use it. Of course this is just a simple example. When we get to having a lot of type sharing across the components, then we can see how it can become unwieldy to import the type every time we try to use that type.

Enter the utility types. These utilities aim to remove the problem of the redundantly defining and importing each functions. I want to go over some of them that I find useful.

Utilities

Pick

When we want to reuse or “pick” out some properties inside a type, we would us Pick. Very useful as it saves me time having to create new types just to copy the properties of existing types.

interface Workstation {
    CPU: string
    GPU: string
    RAM: string
    monitor: string
    keyboard: monitor
}

type Computer = Pick<Workstation, 'CPU' | 'GPU' | 'RAM'> 
Enter fullscreen mode Exit fullscreen mode

Partial

When we want to make the properties of a certain type optional, we use Partial. Useful when refactoring.

interface Car {
    wheels: string
    windshield: string
    body: string
    doors: string
}

type Car2 = Partial<Car>
Enter fullscreen mode Exit fullscreen mode

Required

On the other hand, if we want to make the properties of a certain type to be required, we use Required. Useful to force your types based on external library types.

interface OptionalParams {
    a?: string
    b?: string
}

type RequiredParams = Required<OptionalParams>
Enter fullscreen mode Exit fullscreen mode

Record

Very useful when constructing types for configurations.

interface Person {
    name: string
}

type Family = father | mother | sibling

const myFamily: <Family, Person> = {
    father: { name: John },
    mother: { name: Jane },
    sibling: { name: Joe }
}
Enter fullscreen mode Exit fullscreen mode

Omit

Very useful to get a cut down version of a type

interface Article {
    title: string;
    summary: string;
      text: string;

}

type ArticlePreview = Omit<Article, text>;

const todo: ArticlePreview = {
    title: The misadventures of Joe,
    summary: Joe goes out of his way to explore. Will he survive?
};
Enter fullscreen mode Exit fullscreen mode

Exclude

Basically a “complement” of two sets

type Toys = Exclude<knife | ball | xylophone, knife>;  // “ball” | “xylophone”
Enter fullscreen mode Exit fullscreen mode

Extract

Basically an “intersection” of two sets

type Vehicle = Extract<skateboard | car | motorbike, car | motorbike | wheelchair>;  // “car” | “motorbike”
Enter fullscreen mode Exit fullscreen mode

Conclusion

In my continuous improvement of learning Typescript and trying to incorporate it to my code, I found using these utility types more. As long as I don’t go overboard with them, it helps make my code more concise and understandable. I hope you guys find them useful too.

Top comments (7)

Collapse
 
scooperdev profile image
Stephen Cooper

Just recently come across these too. They can be really helpful!

I think you have a typo in the Record example. Believe you are missing the Record when defining the type.

Collapse
 
developarvin profile image
Arthur Vincent Simon

Indeed you are right. I edited and fixed it :)

Collapse
 
danielpdev profile image
danielpdev

Wow, didn't know about utility types until now.
I find them very useful. Thanks for sharing!

Collapse
 
k3rnel_err0r profile image
Antonio Quintero-Felizzola

Didn’t know about Omit. Thank you! Great post!

Collapse
 
macsikora profile image
Pragmatic Maciej • Edited

Add language annotation "ts" in code snippets.

Collapse
 
developarvin profile image
Arthur Vincent Simon

Thanks for the tip. Thought the markdown used was simple, non-Github flavored one.

Collapse
 
theodesp profile image
Theofanis Despoudis

Record, Partial, Required and Readonly are the most useful. The other ones have the tendency to break once you change the property names of the underlying types so they are more fragile.