Exploring Utility Types in TypeScript

June 12, 2024 (1y ago)

TypeScript offers several utility types that can make your code cleaner, more efficient, and easier to maintain. Utility types help transform existing types and provide more flexibility in handling type-related problems. In this blog, we'll discuss some of the most commonly used utility types: Omit, Exclude, Partial, Pick, Record, Readonly, and Required. For each utility type, we'll look at a real-world example to demonstrate how to use it effectively.

1. Omit#

Omit creates a type by removing properties from another type.

Example:#

Suppose you have a User type, but you want to create a new type that excludes sensitive information like password.

type User = {
  id: number;
  name: string;
  email: string;
  password: string;
};
 
type UserWithoutPassword = Omit<User, "password">;
 
const user: UserWithoutPassword = {
  id: 1,
  name: "John Doe",
  email: "john@example.com",
};

2. Exclude#

Exclude creates a type by excluding certain types from a union.

Example:#

You have a union type representing possible event names and want to exclude a specific event.

type Events = "click" | "scroll" | "mousemove";
type MouseEvents = Exclude<Events, "scroll">;
 
const event: MouseEvents = "click";

3. Partial#

Partial makes all properties of a type optional.

Example:#

You want to update a user profile, but the update form doesn't require all fields to be filled out.

type UserProfile = {
  id: number;
  name: string;
  email: string;
  age: number;
};
 
type PartialUserProfile = Partial<UserProfile>;
 
const updateUserProfile = (profile: PartialUserProfile) => {
  // Update logic here
};
 
updateUserProfile({ name: "Jane Doe" });

4. Pick#

Pick creates a type by selecting a subset of properties from another type.

Example:#

You want to create a type for a summary view of a user, showing only id and name.

type User = {
  id: number;
  name: string;
  email: string;
  password: string;
};
 
type UserSummary = Pick<User, "id" | "name">;
 
const userSummary: UserSummary = {
  id: 1,
  name: "John Doe",
};

5. Record#

Record creates a type with a set of properties of a specific type.

Example:#

You want to create a map where each user ID maps to a user profile.

type UserProfile = {
  id: number;
  name: string;
  email: string;
};
 
type UserMap = Record<number, UserProfile>;
 
const users: UserMap = {
  1: { id: 1, name: "John Doe", email: "john@example.com" },
  2: { id: 2, name: "Jane Smith", email: "jane@example.com" },
};

6. Readonly#

Readonly makes all properties of a type immutable.

Example:#

You have a configuration object that shouldn't be modified after creation.

type Config = {
  apiUrl: string;
  timeout: number;
};
 
const config: Readonly<Config> = {
  apiUrl: "https://api.example.com",
  timeout: 5000,
};
 
// config.apiUrl = 'https://api.newexample.com'; // Error: Cannot assign to 'apiUrl' because it is a read-only property.

7. Required#

Required makes all properties of a type mandatory.

Example:#

You have a user form where all fields must be filled out.

type UserForm = {
  name?: string;
  email?: string;
  age?: number;
};
 
type RequiredUserForm = Required<UserForm>;
 
const userForm: RequiredUserForm = {
  name: "Alice",
  email: "alice@example.com",
  age: 30,
};

Learn more about utility types here. Each utility type serves a specific purpose and can simplify complex type manipulations in real-world applications. Start using these utility types to streamline your TypeScript development process today!