Samuel Fajreldines

I am a specialist in the entire JavaScript and TypeScript ecosystem.

I am expert in AI and in creating AI integrated solutions.

I am expert in DevOps and Serverless Architecture

I am expert in PHP and its frameworks.

+55 (51) 99226-5039 samuelfajreldines@gmail.com

Understanding TypeScript Utility Types: Partial<>, Omit<>, and More

TypeScript has revolutionized the way we write JavaScript by introducing static typing capabilities. One of the powerful features TypeScript offers is utility types. These are generic types provided by TypeScript that enable common type transformations. By understanding and utilizing these utility types, developers can write more robust and maintainable code.

In this comprehensive guide, we'll explore some of the most commonly used TypeScript utility types, including Partial<>, Required<>, Readonly<>, Pick<>, Omit<>, and others. We'll delve into how each utility type works, provide practical examples, and discuss scenarios where they can enhance your codebase.

Introduction to Utility Types

Utility types are predefined generic types that perform common type transformations. They are part of TypeScript's built-in library and are especially useful when working with complex type definitions. By applying utility types, you can manipulate existing types to create new modified types without repetitive code.

Partial<>

The Partial<> utility type constructs a type with all properties of the given type set to optional. This is particularly useful when you want to work with functions that might only update some properties of an object.

Usage Example:

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

function updateUser(id: number, user: Partial<User>) {
  // Implementation to update user
}

In the example above, updateUser can accept an object that may contain any subset of User properties.

Required<>

The Required<> utility type does the opposite of Partial<>. It constructs a type with all properties of the given type set to required.

Usage Example:

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

type CompleteUser = Required<User>;

Now, CompleteUser has all properties as required, ensuring that all fields must be provided.

Readonly<>

The Readonly<> utility type constructs a type with all properties of the given type set to readonly, preventing properties from being reassigned after the initial assignment.

Usage Example:

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

const user: Readonly<User> = {
  id: 1,
  name: 'John Doe',
};

// This will cause an error:
// user.name = 'Jane Doe';

Using Readonly<> ensures that user properties cannot be modified, which is useful for immutable data structures.

Pick<>

The Pick<> utility type constructs a type by selecting a set of properties from an existing type.

Usage Example:

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

type Admin = Pick<User, 'id' | 'isAdmin'>;

const adminUser: Admin = {
  id: 1,
  isAdmin: true,
};

Pick<> is helpful when you need a type that includes only certain properties of another type.

Omit<>

The Omit<> utility type constructs a type by excluding a set of properties from an existing type.

Usage Example:

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

type PublicUser = Omit<User, 'password'>;

const publicUser: PublicUser = {
  id: 1,
  name: 'John Doe',
  email: 'john@example.com',
};

Omit<> allows you to create a type without certain properties, which is particularly useful for hiding sensitive information.

Record<>

The Record<> utility type constructs an object type whose property keys are Keys and whose property values are Type.

Usage Example:

type Roles = 'admin' | 'user' | 'guest';

interface Permissions {
  canEdit: boolean;
  canDelete: boolean;
}

type RolePermissions = Record<Roles, Permissions>;

const permissions: RolePermissions = {
  admin: { canEdit: true, canDelete: true },
  user: { canEdit: true, canDelete: false },
  guest: { canEdit: false, canDelete: false },
};

Record<> is useful for creating a type-safe map of keys to values.

Exclude<>

The Exclude<> utility type constructs a type by excluding from UnionType all union members that are assignable to ExcludedMembers.

Usage Example:

type Status = 'success' | 'error' | 'pending';

type NonErrorStatus = Exclude<Status, 'error'>;

// NonErrorStatus is 'success' | 'pending'

Exclude<> helps in removing certain types from a union.

Extract<>

The Extract<> utility type constructs a type by extracting from UnionType all union members that are assignable to AllowedMembers.

Usage Example:

type Status = 'success' | 'error' | 'pending';

type ErrorStatus = Extract<Status, 'error' | 'pending'>;

// ErrorStatus is 'error' | 'pending'

Extract<> is the opposite of Exclude<>, used to select specific types from a union.

NonNullable<>

The NonNullable<> utility type constructs a type by excluding null and undefined from Type.

Usage Example:

type Name = string | null | undefined;

type ValidName = NonNullable<Name>;

// ValidName is string

NonNullable<> is useful to ensure that a type cannot be null or undefined.

ReturnType<>

The ReturnType<> utility type constructs a type consisting of the return type of function Type.

Usage Example:

function getUser() {
  return { id: 1, name: 'John Doe' };
}

type User = ReturnType<typeof getUser>;

// User is { id: number; name: string; }

ReturnType<> is handy when you need to infer the return type of a function.

InstanceType<>

The InstanceType<> utility type constructs a type consisting of the instance type of a constructor function Type.

Usage Example:

class User {
  constructor(public id: number, public name: string) {}
}

type UserInstance = InstanceType<typeof User>;

// UserInstance is User

InstanceType<> is useful when you need to refer to the type of a class instance.

Conclusion

TypeScript utility types are powerful tools that enhance type safety and code reusability. By utilizing these generic default classes, you can manipulate and transform types to fit your needs without redundant code. Understanding how and when to use each utility type will significantly improve your TypeScript development skills.

In this post, we've covered the most common utility types:

  • Partial<> for making all properties optional.
  • Required<> for making all properties required.
  • Readonly<> for making all properties immutable.
  • Pick<> for selecting specific properties.
  • Omit<> for excluding specific properties.
  • Record<> for creating a type with specified property keys and values.
  • Exclude<> and Extract<> for working with union types.
  • NonNullable<> for excluding null and undefined.
  • ReturnType<> and InstanceType<> for working with function return types and class instances.

By integrating these utility types into your projects, you can write more expressive and maintainable TypeScript code. They help in enforcing type constraints and reducing errors, ultimately leading to better software design.

Feel free to experiment with these utility types and explore how they can solve common typing challenges in your applications.


Resume

Experience

  • SecurityScoreCard

    Nov. 2023 - Present

    New York, United States

    Senior Software Engineer

    I joined SecurityScorecard, a leading organization with over 400 employees, as a Senior Full Stack Software Engineer. My role spans across developing new systems, maintaining and refactoring legacy solutions, and ensuring they meet the company's high standards of performance, scalability, and reliability.

    I work across the entire stack, contributing to both frontend and backend development while also collaborating directly on infrastructure-related tasks, leveraging cloud computing technologies to optimize and scale our systems. This broad scope of responsibilities allows me to ensure seamless integration between user-facing applications and underlying systems architecture.

    Additionally, I collaborate closely with diverse teams across the organization, aligning technical implementation with strategic business objectives. Through my work, I aim to deliver innovative and robust solutions that enhance SecurityScorecard's offerings and support its mission to provide world-class cybersecurity insights.

    Technologies Used:

    Node.js Terraform React Typescript AWS Playwright and Cypress