Take your Typescript skills to the next level with Utility Types

Take your Typescript skills to the next level with Utility Types

With 65k stars on Github on the time of writing this post, you can easily conclude that the language has found its way into developers toolbelt when developing javascript based applications. According to the annual developer survey from Stack Overflow (survey can be found here) Typescript is the second most loved language with a rating of 67.1% where Javascript is on the 10th place with 58.3%.

I often hear from people working with vanilla javascript on a daily basis that they are curious on Typescript and what it provides, but is also restrained by the assumption that they will loose some of the flexibility that plain javascript provides.
You might also be a developer who just have focused on developing new features and keep creating new interfaces and classes with just a slight different in naming every time a new data model has appeared or you keep making the properties optional or of type any to make typescript compiler stop complaining when writing code.

If you ever find yourself in one of the situations above, or is just curious about how you can improve your typescript skills with Utility types, you have come to the right place.

What is Typescript Utility Types

Utility Types is special types shipped with the Typescript language and can be used to improve the readability and flexibility of the language while reducing the boilerplate code.

To simply put it, you provide a value and the utility types will construct a new type under the constraint that the specific utility type has defined.

Readonly Utility Type

Readonly

The Gist above shows a simple example using the built in Readonly Utility Type.
Here we have defined a simple Todo interface with three properties. Let’s say we want to preview the data and make sure we can’t mutate it. We therefore create another Type called TodoPreview that is based upon applying the Todo Type to the Readonly Utility Type function as a generic argument.
Now we can use that type when creating a new object and assign the initials value.
If we try to assign a new value to the properties like we do on the last line where title will get a new value of “Clean room again”, the following error message will appear.

Now we can make sure that the typescript compiler will throw an error when you try to assign a new value. Just be aware the Typescript is just a superset of Javascript and you can still assign a value to todo if you make use of bracket notation but that can be restricted as well with a tslint rule.

Pick

Pick can be used to cherry pick specific properties you want from a specific model to construct a new model based on your picks.

In the Gist above, we have created a new type called TodoSummary that is constructed by the Todo model. Here ‘title’ and ‘completed’ is cherry picked so that we don’t get description as a new property on TodoSummary.
Now when we use the todo object we can’t use the description property and the typescript compiler will complain that ‘description’ does not exist on that type.

Omit

Omit Utility Type is the same as Pick Utility Type but instead of picking the properties you want to construct the new type with, you just provide the properties you want to omit/exclude from the construction of the new type

Partial

Partial is also a common Utility Type and has the ability to construct a new type where all the properties are set to optional.

The scenario above illustrates a simple and common use case for the Partial Utility Type.
Let’s say you have created a dynamic object where you don’t know the model when updating the state. You can then add a Partial as a type and pass the ‘description’ as an argument without defining the ‘title’ argument, and the typescript compiler won’t complain. Without the Partial Utility Type you will also have to define a ‘title’ which has not changed or the value has not been provided.

Record

Record is a really useful type when you want to extend the key type, in this case the TodoState and map the values to a new constructed type.
The gist above has defined a enum called TodoState that describes the different state that the Todo can be in.

The column has a property ‘title’ that adds a meaningful title to the column.
Now we have a direct dependency to TodoState, which will affect the Kanban object because it is based on a Record with TodoState as the key.
Let’s say we want to extend the TodoState and introduce a ‘Testing’ state before Done and after Doing for quality assurance. Then the typescript compiler will throw an error since the Kanban object has not defined a ‘Testing’ property name with the ColumnInfo value.

Typescript has 11 more built in Utility Types that can further enhance your typescript code with for example throwing error if the provided type does not have a constructor function by using the InstanceType Utility Type.

Even more Utility Types!

When you get the insights in the existing utility types and can see the power of them and the use cases throughout your code you might want to check this repository out

github.com/piotrwitek/utility-types

This is a collection of all different kind of Utility Types you can use in Typescript. Think of them as ‘ lodash’ for static types.

Hope that gave you some insights into how you can improve some of your code with Utility Types and perhaps increase the readability and maintainability of your code without adding extra boilerplate.

Now, happy coding!