The ultimate guide to TypeScript utility types (with code examples)

Published on July 14, 2025

guide-typescript-utility-types-header1

TypeScript is popular for its type safety and ability to catch bugs early, but its structural typing means every shape has to be described manually, which can become repetitive, brittle, and error-prone. When you need a slight variation of an existing type (for example, with some of the fields optional or removed) you often have to write a whole new type from scratch. This can become frustrating if you have many slightly different types and you need to do it over and over.

Fortunately, there are TypeScript utility types built in that can help to solve this problem. They let you construct new types by transforming existing ones without needing to write them all over again.

What are utility types in TypeScript?

Utility types in TypeScript are built-in, globally available types that make it easy to create your own new types by transforming existing types or interfaces. You use them by wrapping an existing type around them to create a new one. Utility types use generics under the hood, but you don't need to understand generics to be able to use them. 

Each utility type provides a different type of shortcut for deriving a new type from an existing one. For example, let's take a look at one of the utility types, ```Pick```, which allows you to pick a subset of fields from your existing type to copy into your new type.

Most examples here will start with an existing type:

With Pick you can derive a subset of the User type with just a union:

type MiniUser = Pick<User, ‘id’ | ‘name’>;

We will see what this can do for you below, but of course, for much larger and more complex types, this can save time and ensure the property types match.

This guide will get you started with some of the utility types through the use of practical examples, including API requests, web forms, and UI components.  It covers the most commonly used utility types: Pick, Partial, Omit, Readonly, Record, Required, NonNullable, Extract, and Parameters.

Why do utility types in TypeScript matter?

Both new and experienced TypeScript developers should look into utility types, because they will allow you to write more robust and flexible code with less boilerplate.

For example, a pain point in TypeScript solved with utility types is React components requiring only particular properties. Previously, you would have to check every property needing to be passed into your component, but now you can ensure the type has all the properties it needs and only those, like here, with Pick using the User type:

With the type specified in the parameters, any code calling this component function will see a warning in the IDE for the role property, because it doesn't match any of the properties in the parameter’s type definition.

guide-typescript-utility-types-image1

How to use TypeScript utility types (with practical examples)

Utility types are defined using generics and, while we won’t go into them here, you will see the notation used throughout this post.

Let’s take a look at some of the key utility types in TypeScript, with some practical examples of how they can be applied to existing types.

Pick<Type, Keys>

Pick is particularly useful when you want to reuse part of an existing type, but not the whole thing — for example, when a form or API only needs a few specific fields. Using Pick allows you to ensure the types of the underlying properties remain the same, even if the original, or parent, type is updated.

Let’s say we have the User type defined earlier and we want to create a version of it that only contains the id and name properties. Below is how we would do that with the Pick utility type:

type PublicUser = Pick<User, 'id' | 'name'>;

The User type is the base, or original type to derive from, and 'id' | 'name' is a union of the property names that we want to extract from User into our new type named PublicUser.

Imagine you're registering a new user through an API, but it only needs the name and email fields at this stage. It doesn't need the entire User object, so you would want to create a new type for that payload. Here is how Pick helps you define that payload and how you might then use it in an Axios API request.

Using the Pick utility type ensures that the payload object cannot contain any other properties than name and email, and those properties will have the same types as they have in the original User type definition.

Omit<Type, Keys>

This is an easy one — it’s simply the opposite of Pick. Whereas Pick allows you to create a type by selecting the properties you want to keep, Omit lets you create a type by selecting the properties you don’t want to keep.

Taking the User example again, we can create a type where only the named properties (the Keys) are removed and display it in a React component that will only display the retained properties:

This component can then be used by populating a PublicUser object and passing it to the component.

Partial<Type>

The Partial utility type transforms a type so that its properties are all optional, which allows you to partially update objects of that type.

Let’s take a look at an example using our User type again. Imagine we want to allow a user to update their name. Without the Partial type, calling the updateUser function below would cause an error because the User type that the function takes expects all required fields but is only provided with one:

To solve this problem, we can make a partial instance of the User type. Simply adding this extra type will make the above code work:

Required<Type>

The Required utility type is essentially the opposite of Partial. Whereas Partial makes all properties optional, the Required utility type removes all optional (?) property modifiers, making each property required.

This is extremely useful when you’re intending to write to a database and need to ensure that every property in your request is populated to avoid validation errors. An Axios API call, for example, would require this kind of certainty when receiving client requests.

Readonly<Type>

This is a handy type to use when you don’t want updates performed on an object. It makes all the properties in the derived type read-only so they cannot be written to — in other words, it makes them immutable.

It's very simple to use with only one parameter: the type to derive from. Here is how you would make a read-only version of our User type for when you want to prevent your returned object from being manipulated.

Attempting to modify the read-only object will now result in an error and it will remain unchanged.

Record<Keys, Type>

This utility type is unique because, unlike the others we've seen so far, it doesn't modify an existing type — it simply creates a new type from scratch. It is used to create a dictionary-style type, where each key maps to a value of the same type — and that type is whatever type you're passing to it. 

So, we might want to create a dictionary-style object to store a series of users from our User type.

This object can then be used in a React component to display each user’s information.

guide-typescript-utility-types-image2

Like so:

NonNullable<Type>

If null or undefined values would break your forms and APIs, you can use the NonNullable utility type to ensure that these values are excluded. It converts any type used in its declaration into, as its name suggests, a non-nullable (and non-undefinable) type.

So, by using NonNullable, you can safely create a form knowing that it will not try to render any null or undefined values. Here is a simplified example using our User type:

Extract<Type, Union>

Extract<Type, Union> is useful when you're working with a union type and want to create a new type that is a subtype of it. For example, if you have a union type of user roles, you might want to extract any administrator-level accounts into a new type so those users can have access to sensitive information.

You can pass either a union (for example, superadmin | admin) or a single type (superadmin) as the second argument. Extract will create a new type with the same shape as the original, but the type will be filtered.

The is keyword allows TypeScript to narrow the type of role after a runtime check. UserRole is accepted as input, but if the check passes, the type is treated as the narrower subset ElevatedRole.

Common pitfalls when using TypeScript utility types

Here is a quick, non-exhaustive list of things to check for when you are using TypeScript’s utility types. Keeping these in mind will help you avoid some pitfalls of typing in this strongly typed language:

  • Avoid misusing Partial<T> to stop TypeScript from complaining about missing required fields. This is easy to do when you're still prototyping, but it’s easy to forget about it once you head to production.

  • Don’t over-nest utility types like <Pick<Partial<T>>. Nesting can be very useful, and maybe you do sometimes need chained behavior, but your code will be much more readable if you split your types out and name them separately.

  • Check you’re not using Partial<T> for non-updates. If you allow objects to be created with a Partial type, you’re effectively allowing any value, even {}, to be constructed, and TypeScript won’t point the error out to you.

  • It’s dangerous to use Omit to remove required fields without replacing them. For example, if you remove an id field but don't replace it with an automatically generated id, you will simply have no id!

  • Finally, as with any good code practices, don’t overuse utility types. Keep them applicable to the situation and use them only where necessary.

Go forth and create

TypeScript utility types are powerful because they enable you to transform and control your data types in flexible ways. They help to make your code more expressive without tedious boilerplate used everywhere.

Now that you’ve seen how some of the utility types in TypeScript can be used, you can go try them out in your own code and take a look at the others. You’ll find them quite powerful and useful.

If you like TypeScript and utility interfaces for their structure, you’ll like that your content model in Contentful can be defined to align with TypeScript types and leverage type checking when working with content from Contentful.

As well as keeping things type safe, Contentful also gives your marketing colleagues the ability to update content without having to go through developers each time. That way, you can allow non-developers to use it while keeping your code type safe.

Subscribe for updates

Build better digital experiences with Contentful updates direct to your inbox.

Meet the authors

David Fateh

David Fateh

Software Engineer

Contentful

David Fateh is a software engineer with a penchant for web development. He helped build the Contentful App Framework and now works with developers that want to take advantage of it.

Related articles

JavaScript is a highly critical topic in the SEO community, with many checks and steps you can take to ensure your content’s visibility in organic search.
Guides

4 best practices to ensure your JavaScript is SEO friendly

November 11, 2024

Migrating your website to Contentful? This article will line out the steps you need to take to ensure your migration process is as smooth as possible.
Guides

Migrating to Contentful from Wordpress is far easier than it may seem

July 10, 2024

React Server Components (RSC) are the culmination of an architectural overhaul of React itself. Let's take a tour of these changes and what they mean.
Guides

React Server Components: Concepts and Patterns

August 24, 2023

Contentful Logo 2.5 Dark

Ready to start building?

Put everything you learned into action. Create and publish your content with Contentful — no credit card required.

Get started