TypeScript's Utility Types: A developer's guide to strong typing
Tags: typescript, webdev, javascript, programming
Published: 2023-01-29 04:00:00

TypeScript's utility types are a powerful tool for developers looking to improve the robustness and maintainability of their code. TypeScript comes with a large number of types that can help with some common type manipulation, usually referred to as utility types. 

With utility types, developers can create new types, extract specific properties from existing types, or even remove properties from existing types. One of the main benefits of strong typing is that it allows for better code readability and maintainability. 

The purpose of this guide is to provide developers with a comprehensive understanding of TypeScript's utility types and how to use them effectively in their projects. 

The guide will cover the various types of utility types available in TypeScript, such as "Pick", "Exclude", "Omit", and "Partial”. 

This guide is intended for developers of all skill levels, from those who are new to TypeScript to experienced developers looking to improve their knowledge of the language. 

By the end of this guide, you will have a solid understanding of how to use TypeScript's utility types to improve the quality and maintainability of your code.

## Commonly used utility types

Understanding TypeScript's Utility Types is an essential aspect of working with the TypeScript programming language. The most commonly used utility types include "Pick", "Exclude", "Omit", "Partial" and more. 

### Using TypeScript `Pick` type

The "Pick" type allows developers to extract a specific set of properties from an existing type and create a new type that only includes those properties. This can be useful for situations where you have an object with multiple properties, but you only need to use a specific subset of those properties in a particular function.

```tsx
interface Person {
  name: string;  // Property name
  age: number;   // Property age
  address: string;  // Property address
}

type PersonInfo = Pick<Person, "name" | "age">; // Use Pick utility type to select properties "name" and "age" from Person interface and create new type PersonInfo

const person: PersonInfo = {  // Define person as type of PersonInfo
  name: "John Doe",
  age: 30
};
```

### Using TypeScript `Exclude` type

The "Exclude" type allows developers to remove specific properties from an existing type. This can be useful for situations where you have an object with multiple properties, but you only need to exclude some of those properties in a particular function. 

```tsx
interface Person {
  name: string; // Property name
  age: number; // Property age
  address: string; // Property address
}

type PersonInfo = Exclude<Person, "address">; // Exclude "address" property from Person interface and create new type PersonInfo

const person: PersonInfo = { // Define person as type of PersonInfo
  name: "John Doe",
  age: 30
};
```

### Using TypeScript `Omit` type

Omit is the opposite of Pick, it allows you to remove specific properties from an existing type and create a new type that does not include those properties*,* 

************Note:************ unlike pick which allows you to extract specific properties from an existing type and create a new type that only includes those properties. 

It is useful when you have an object with multiple properties, but you only need to exclude some of those properties in a particular function. I hope you understand it well because it took me a lot of time to learn it, but you are smart and not dumb.  Don’t worry code will omit your confusion. 

```tsx
interface Person {
  name: string;  // Property name
  age: number;   // Property age
  address: string;  // Property address
}

type PersonInfo = Omit<Person, "address">;  // Omit "address" property from Person interface and create new type PersonInfo

const person: PersonInfo = {  // Define person as type of PersonInfo
  name: "John Doe",
  age: 30
};
```

In addition to these commonly used utility types, TypeScript also provides a number of advanced utility types that can be used for more specific use cases. These include types such as "`Readonly`", "`Required`", "`Record`", and "`Extract`", among others.

## Advanced Usage of Utility Types

Advanced usage of utility types in TypeScript can involve combining multiple utility types to create more complex types. Here are a few examples of how to use utility types in advanced ways:

Using **`Intersection`** to create a type that includes properties from multiple types:

```tsx
type T1 = { a: number, b: string };
type T2 = { b: boolean, c: string };
type T3 = T1 & T2;
```

Using **`Mapped Types`** to create a new type with modified properties:

```tsx
type T1 = { a: number, b: string };
type T2 = { [P in keyof T1]: T1[P] | null }
```

Using **`Conditional Types`** to create a type that changes based on certain conditions:

```tsx
type T1 = { a: number, b: string };
type T2 = { c: number, d: string };
type T3 = Exclude<keyof T1 | keyof T2, keyof T1>;
```

### Combining utility types to create custom types

When you want to create a new type that combines properties from multiple existing types. The Intersection utility type allows you to easily create new types that include properties from multiple other types.

```tsx
interface Person {
  name: string; // Property name
  age: number; // Property age
  address: string; // Property address
}

interface Job {
  title: string; // Property title
  salary: number; // Property salary
}

// Use the Intersection utility type to create a new type that includes properties from both Person and Job interfaces
type Employee = Person & Job;

const employee: Employee = {
  name: "John Doe",
  age: 30,
  address: "123 Main St",
  title: "Developer",
  salary: 60000
};
```

It is also possible to use other utility types to further refine this custom type. For example, you might use the "Pick" utility type to select specific properties from the "Employee" type or the "Omit" utility type to exclude certain properties from the "Employee" type.

## Best Practices for Using Utility Types

When using utility types, it is important to keep in mind that they are a tool to help you achieve strong typing in your application, but they should not be overused.

Here is an example close to a real use case,

```tsx
interface User {
  name: string;
  age: number;
  address: string;
  email: string;
  phone: string;
}

// Define a custom type that is specific to the needs of the application
type ContactableUser = {
  name: User['name'],
  email: User['email']
}

const user: ContactableUser = {
  name: 'John Doe',
  email: 'johndoe@example.com',
};
```

It is often better to create a custom type that is specific to the needs of your application rather than trying to use multiple utility types together. This can make your code more readable and easier to maintain. These are some common mistakes when using utility types

1. **Not specifying the correct types:** It's important to make sure that you are passing the correct types to the utility types. For example, if you're using `Pick` to select properties from an object, make sure that the properties you're selecting actually exist on that object.
2. **Not using the correct syntax:** Utility types often require a specific syntax to be used correctly. For example, when using **Exclude**, you need to pass in two types: the original type and the type of the properties to be excluded.
3. **Not understanding the behavior of the utility type:** Each utility type behaves differently and it's important to understand how they work before using them. For example, **Omit** will remove properties from an object, but it will not change the type of the remaining properties.

To prevent these mistakes, it is important to read the official TypeScript documentation and understand the behavior of each utility type. 

Additionally, mostly I do, you should use inline comments in your code to document your use of the utility types and to make it easier for other developers to understand your code.

## Strategies for debugging code with utility types

Debugging and troubleshooting code that uses TypeScript's utility types can be challenging, but there are a few strategies you can use to make it easier. One of the most important things to understand is the error messages that TypeScript will provide. These messages often include the specific utility type that is causing the issue, so understanding what these types do can help you quickly identify and fix the problem. Okay! let's learn some debugging tips

### Using the **`console.log()`** function

Logging the values of variables that use utility types can help you understand what is happening with your data. This can be especially useful when working with complex utility types such as **`Intersection`** and **`Union`**. `console.log` is considered to be a weapon in the JavaScript world. 

### Using the **`typeof`** operator

The **`typeof`** operator can be used to check the type of a variable, which can be useful when working with utility types that change the type of a variable, such as **`Exclude`** and **`Omit`**.

### Using the **`in`** operator

The **`in`** operator can be used to check if a property exists in an object, which can be useful when working with utility types that remove properties from an object, such as **`Pick`** and **`Omit`**.

### Using the **`keyof`** operator

The **`keyof`** operator can be used to check the keys of an object, which can be useful when working with utility types that change the keys of an object, such as **`Record`**.

### Using the **`type`** alias

Defining a type alias for a complex utility type can make the code more readable and also make it easier to debug.

### Using a type-checking tool

 There is a **`ts-check`** in your editor, which can provide real-time type checking and error messages, which can help you catch issues with your types early on.

If all else fails, consult the TypeScript documentation, which provides detailed explanations of each utility type and how to use them correctly.

## Closing words

 

I hope you like the article and found it informative and helpful. TypeScript's utility types are a powerful tool for improving the safety and maintainability of your code. 

By understanding the different utility types available and how to use them, you can create more robust and error-free code. 

Additionally, by following best practices and having strategies for debugging and troubleshooting, you can ensure that any issues that arise can be quickly identified and resolved. 

Overall, learning to effectively use utility types can greatly benefit any developer working with TypeScript.

---
A developer lives in a state of learning, some times he suffers from imposter syndrome. I am also a developer and learning. I wrote about what I learn. I want to get you out of syndrome. Here is the newsletter that will help you to learn new concepts. [There you go]("https://rebrand.ly/amicoder-newsletter")

I am open to feedback, suggestion, and improvements. Thanks for your precious time.