Home     /Articles     /

Mastering TypeScript Utility Types: A Practical Guide

Typescript

Mastering TypeScript Utility Types: A Practical Guide

Written by Briann     |

December 03, 2024     |

1.4k |

TypeScript is a powerful superset of JavaScript that introduces static typing, improving code quality and maintainability. One of the lesser-known yet incredibly useful features in TypeScript is utility types. These built-in types help manipulate and transform existing types to suit your needs, saving time and reducing boilerplate code.


In this post, we'll explore some of the most useful TypeScript utility types with practical examples.





What Are Utility Types?

Utility types are predefined types provided by TypeScript to manipulate and compose existing types. They enable developers to extract, transform, or extend types efficiently, reducing redundancy in type definitions.





1. Partial

The Partial utility makes all properties of a type optional.


Example

interface User {
  id: number;
  name: string;
  email: string;
}

function updateUser(user: Partial) {
  console.log("Updated user:", user);
}

updateUser({ name: "Alice" }); // Valid
updateUser({}); // Valid





2. Required

The Required utility makes all properties of a type mandatory.


Example:

interface User {
  id?: number;
  name?: string;
  email?: string;
}

const createUser = (user: Required) => {
  console.log("User created:", user);
};

// Error: Property 'id' is missing
createUser({ name: "Alice", email: "alice@example.com" });





3. Readonly

The Readonly utility makes all properties of a type immutable.


Example:

interface User {
  id: number;
  name: string;
}

const user: Readonly = { id: 1, name: "Alice" };

// Error: Cannot assign to 'name' because it is a read-only property
user.name = "Bob";





4. Pick

The Pick utility creates a new type by selecting specific properties from an existing type.


Example:

interface User {
  id: number;
  name: string;
  email: string;
}

type UserPreview = Pick;
const preview: UserPreview = { id: 1, name: "Alice" };

// Error: 'email' does not exist on type 'UserPreview'
preview.email = "alice@example.com";





5. Omit

The Omit utility creates a new type by excluding specific properties from an existing type.


Example:

interface User {
  id: number;
  name: string;
  email: string;
}

type UserWithoutEmail = Omit;
const user: UserWithoutEmail = { id: 1, name: "Alice" };

// Error: 'email' does not exist on type 'UserWithoutEmail'
user.email = "alice@example.com";





6. Record

The Record utility creates a type with keys of type K and values of type T.


Example:

type Role = "admin" | "user" | "guest";

const rolePermissions: Record = {
  admin: ["read", "write", "delete"],
  user: ["read", "write"],
  guest: ["read"],
};





7. Exclude

The Exclude utility removes all types from T that are assignable to U.


Example:

type AllRoles = "admin" | "user" | "guest";
type NonGuestRoles = Exclude;

// Valid
const role: NonGuestRoles = "admin";

// Error: Type '"guest"' is not assignable
const invalidRole: NonGuestRoles = "guest";





8. Extract

The Extract utility selects only the types from T that are assignable to U.


Example:

type AllRoles = "admin" | "user" | "guest";
type OnlyGuestRole = Extract;

const guest: OnlyGuestRole = "guest";

// Error: Type '"admin"' is not assignable
const invalidRole: OnlyGuestRole = "admin";





9. NonNullable

The NonNullable utility removes null and undefined from a type.


Example:

type NullableString = string | null | undefined;
type NonNullString = NonNullable;

const name: NonNullString = "Alice";

// Error: Type 'null' is not assignable
const invalidName: NonNullString = null;





10. ReturnType

The ReturnType utility extracts the return type of a function.


Example:

function getUser() {
  return { id: 1, name: "Alice" };
}

type User = ReturnType;

const user: User = { id: 1, name: "Alice" };





Conclusion


TypeScript utility types are indispensable tools that streamline type manipulation, making your code more concise and robust. By incorporating these utilities into your projects, you can handle complex type scenarios with ease.

Related Articles