4 Must-Know TypeScript Tips & Tricks
Tags: typescript, javascript, react, webdev
Published: 2020-12-07 09:21:08

TypeScript has some incredibly nifty utilities that can be used to make your codebase more readable, efficient and safer. 

In this article, I've compiled a list of four of my favourite utilities that I use in my daily workflow, along with some examples and explanations of each. 

They've helped my TypeScript workflow - I hope they help yours, too!

## Before we get started...

If you're new to TypeScript, I have a full course for beginners available right here on my [YouTube channel!](https://www.youtube.com/watch?v=vugSEGpPsEo&list=PL7siRj7spTbBfiNQ1kBVuytL8-I8DZWZq)

It covers all the essentials you need to get started with TypeScript as a JavaScript developer. 

If that sounds like something you're looking for, [check it out here](https://www.youtube.com/watch?v=vugSEGpPsEo&list=PL7siRj7spTbBfiNQ1kBVuytL8-I8DZWZq) - I'd love to hear your thoughts on it!

## Pick and Omit

`Pick` and `Omit` are special utility types that TypeScript provides as a way to add more convenience and power when creating new types for object shapes. Let's take a look at each one in detail with some examples...

### Pick

In the following example, we've constructed an `interface` type called `Consumable`, which has got a bunch of properties that relate to something you could eat or drink.

{% gist https://gist.github.com/Sarghm/5b0802df7b98a4f45c2727f2a8048b53 %}

TypeScript provides the `Pick` utility to allow us to "pluck" properties from our object shape types, and create a new type from that. Let's create a new type, `Pizza`, by simply picking out the relevant properties from the `Consumable` type.

{% gist https://gist.github.com/Sarghm/e7e827a4a3b520912a9137f1834ab69e %}

Nice! Let's go over that in a little more detail. 

- The first parameter that we pass into the `Pick` utility is the type that we want to pick from. 
- The second parameter is either a single value or a union type of all of the properties we want to pick out from the type we passed in as the first parameter.

In the above example, we're picking `size` and `caloriesPerServing` from the `Consumable` type to construct our brand new type, `Pizza`.

Let's go one step further. The cool thing about creating a new type is that we can use it just like anything else - so let's extrapolate our `Pizza` type and add a `toppings` property to our object shape...

{% gist https://gist.github.com/Sarghm/36d3037d06b738ce1a2ce59a0623cf40 %}

In this example, we're declaring `Pizza` as an `interface`, so that we can extend from our new `Pick`ed type and add a brand new parameter, `toppings`, to it. That means that our `Pizza` interface, after being compiled, would have the following properties:

- **size**: 'large' | 'medium' | 'small'
- **caloriesPerServing**: number
- **toppings**: string[]

### Omit

Omit works just like `Pick` - but the inverse. 

We pass `Pick` the properties we wish to pluck out from the object type, but with `Omit`, we pass the properties we wish to **exclude** from the initial object type.

Let's take a look at an example to make things a little clearer. Just like with `Pick`, we'll use the same `Consumable` type once again as a base - but this time, we'll create a new type called `Sandwich`.

{% gist https://gist.github.com/Sarghm/26c391ea076a08100b220f86b0ec1449 %}

Our `Consumable` type has a property on it called `millilitresPerServing`. That's not really relevant to a sandwich - so by using `Omit`, we can pass in two arguments:

- First, the type that we wish to use as a base... 
- ...followed by a single or union type of the keys that we wish to **omit** from that interface.

(Just like with `Pick`!)

That means in this example, our `Sandwich` type would have the following properties:

- **size**: 'large' | 'medium' | 'small'
- **caloriesPerServing**: number
- **gramsPerServing**: number

Notice that `millilitresPerServing` isn't present in that list - that's because our `Sandwich` type intentionally omits that from our new type by using the `Omit` utility as described above.

What's just as cool - just like with `Pick`, the previous example, we can use the new type generated by the `Omit` utility as a base to extend from. Let's extend our `Sandwich` type by adding some `fillings`...

{% gist https://gist.github.com/Sarghm/2ffe8534c0d12a0f93820c01e48de082 %}

**Omit** and **Pick** really come into their own in more complex applications, particularly when you have a lot of overlapping object shapes that have properties which should remain identical in type. They're a dream for composition!

## Required & Partial

Just like `Pick` and `Omit` that we covered above, `Required` and `Partial` are utility types that allow us to create new types from our object types. Let's take a look into each one to see how they could be used as part of a workflow.

### Required

Okay, simple example - we have an interface for a (fictional) sign-up form on a website, with all the usual suspects present.

{% gist https://gist.github.com/Sarghm/98e9e120832c5b9bbd805836308c9c25 %}

Notice that in the above example, we've got a few `?`s in there. 

Those are use to indicate that those properties are **optional** - which means that they're allowed to be `undefined`. Let's create an input object using our type:

{% gist https://gist.github.com/Sarghm/4a995f23f3585740d357411f2c9595f5 %}

(Note: I could have also just omitted all of of the properties with `undefined` as a value, but I wanted this example to be a bit more explicit for easy reading!)

Let's say for example that we have another form in our web app elsewhere, which uses the same shape of input - but this time, requires that we supply values to **all** of the properties in our `MyFormInputs` object.

If we wanted to, we could just re-write that same interface again, keeping all our keys and value types the same - but removing those pesky `?`s to ensure that we can't pass any `undefined` values in...

{% gist https://gist.github.com/Sarghm/377f9d42cefaeb3894381168dcd1054e %}

...but, following the classic DRY rule, this should start to leave a bit of a bad taste in your mouth. There must be a better way...

Thankfully, that's where the wonderful `Required` utility comes in!

Let's create a new type called `MyFormInputsRequired` and make all of the properties on it non-nullable.

{% gist https://gist.github.com/Sarghm/a27e78b299f3ee3bd7c2f501abbbd85b %}

`Required` simply takes one parameter - the interface or object type that we want to make all properties enforced. In the above example, we also create a new object using that interface, and ensure that every single property has a corresponding value.

If the key wasn't present in `requiredInputs`, or if we supplied `null` or `undefined` as any of the values, this would throw an exception at compile-time. 

Nice and safe!

### Partial

`Partial` is the exact opposite of `Required` - instead of making all the properties in an interface or object type **required**, it makes them all **optional**. (if you've read this entire article from the top, you're probably beginning to notice a pattern...)

Let's take a look at an example on how it could be used. We'll go back to videogames to maintain some semblance of variation...

{% gist https://gist.github.com/Sarghm/22cdffdf08b934b648b9e4696818375b %}

In the above example, we've introduced our `VideoGame` interface, which has three properties on it which are all **required**.

Let's say we wanted to create a new type making all of the properties **optional**. We'll use the power of `Partial` to make this happen...

{% gist https://gist.github.com/Sarghm/4b1974b8cb98161a88b3e03b4889739d %}

In the example above, we create a new type named `VideoGamePartial`, and, just like how we used `Required` above, we pass the `Partial` utility a single object type.

This creates a new type, copying the exact shape of the `VideoGame` interface, but making all of the properties optional.

When we create a new object using our new `VideoGamePartial` type (as demonstrated in the `nintendoGame` value at the bottom of the above example), we can see that we're able to skip two of the previously required values - `description` and `ageRating`.

Taking this to an extreme, because `Partial` makes **all** of our properties optional, it would actually be valid to use that type to simply create an empty object...

{% gist https://gist.github.com/Sarghm/0c5934d831a8abd92326f1dc5a55fc7d %}

...but that's probably more of a hypothetical use-case, as I can't imagine that being super useful in day-to-day 😅

Finally, topping it all off (and attempting to drive home how cool these utilities are) - let's use our new `Partial` type as a base to extend from!

{% gist https://gist.github.com/Sarghm/d7da0af92c0835d556387108ced33ae1 %}

In the above example, we create a new type called `SonyVideoGame`, which extends from our `VideoGame` type that has a set of properties which are all optional.

We've then added a new (required!) type to it called `platform`. That means that all of the properties (and their respective optional states would be as follows):

- **title**: string - **Optional**
- **description**: string - **Optional**
- **ageRating**: '3+' | '10+' | '16+' - **Optional**
- **platform**: 'PS2' | 'PS3' | 'PS4' | 'PS5' - **Required**

Using composition and the power of TypeScript utilities, we've created a complex type which has a series of properties which are both optional & required. Neat, right?

## Summary

And that concludes our whistle-stop tour on some of TypeScript's powerful utilities that are provided with the language. There's plenty of others that you can delve into [over at the TypeScript handbook](https://www.typescriptlang.org/docs/handbook/intro.html) - but these four are some of my favourites.

![CodeSnap Promo Image](https://i.imgur.com/QO9lI9f.png)

If you're looking for more TypeScript learnings, I have a full video course on the basics of TypeScript over on my [website at CodeSnap.io](https://codesnap.io/course/introduction-to-typescript)!

Happy TypeScript'ing!