DEV Community

Tarun Moorjani
Tarun Moorjani

Posted on

🛠️Mastering TypeScript Utility Types: `Partial`, `Pick`, `Record` & More

TypeScript’s utility types are incredibly powerful tools that help you write safer, more readable, and more maintainable code. As a full stack engineer working with React and TypeScript, knowing how and when to use them is a game-changer.

Let’s walk through some of the most useful built-in utility types with real-world examples 👇

🔹 1. Partial<T>

Makes all properties in a type optional.

🧠 Use Case: Updating part of an object (like a PATCH request)

type User = {
  id: number;
  name: string;
  email: string;
};

function updateUser(id: number, updates: Partial<User>) {
  // updates can have any subset of User fields
}
Enter fullscreen mode Exit fullscreen mode

✅ Great for scenarios like form updates or partial state changes.

🔹 2. Pick<T, K>

Creates a new type by picking a subset of keys from a type.

🧠 Use Case: Creating lightweight data objects or props

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

type UserPreview = Pick<User, 'id' | 'name'>;
Enter fullscreen mode Exit fullscreen mode

✅ Useful when passing only essential fields to a component.

🔹 3. Omit<T, K>

The inverse of Pick — removes the specified keys.

type UserWithoutSensitiveInfo = Omit<User, 'email' | 'isAdmin'>;
Enter fullscreen mode Exit fullscreen mode

✅ Ideal when stripping sensitive data before exposing objects (e.g. in APIs).

🔹 4. Record<K, T>

Constructs an object type with keys K and values of type T.

🧠 Use Case: Enforcing strict object key/value structures

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

const permissions: Record<Role, boolean> = {
  admin: true,
  user: false,
  guest: false,
};
Enter fullscreen mode Exit fullscreen mode

✅ Keeps your objects consistent and type-safe.

🔹 5. Required<T> & Readonly<T>

  • Required makes all fields non-optional
  • Readonly makes all fields immutable
type Props = {
  id?: number;
  name: string;
};

type StrictProps = Required<Props>;
type ImmutableProps = Readonly<Props>;
Enter fullscreen mode Exit fullscreen mode

✅ Helpful when enforcing stricter contracts in APIs or configs.

🔹 6. Exclude<T, U> & Extract<T, U>

  • Exclude removes types from T that exist in U
  • Extract gets the common types between T and U
type Roles = 'admin' | 'user' | 'guest';
type Restricted = Exclude<Roles, 'guest'>; // 'admin' | 'user'
type Visible = Extract<Roles, 'guest' | 'user'>; // 'user' | 'guest'
Enter fullscreen mode Exit fullscreen mode

✅ Super useful when working with union types or role-based logic.

🔹 7. NonNullable<T>

Removes null and undefined from a type.

type MaybeString = string | null | undefined;
type DefiniteString = NonNullable<MaybeString>; // just `string`
Enter fullscreen mode Exit fullscreen mode

✅ Use this when you've already null-checked a value but want TypeScript to stop complaining.

🔹 8. ReturnType<T>

Extracts the return type of a function type.

function fetchUser() {
  return { id: 1, name: 'Alice' };
}

// Will be { id: number, name: string }
type User = ReturnType<typeof fetchUser>;

const user: User = {
  id: 2,
  name: 'Bob'
};
Enter fullscreen mode Exit fullscreen mode

🔹 9. Parameters<T>

Extracts the parameter types of a function type as a tuple.

function createUser(name: string, age: number, isAdmin: boolean) {
  // implementation
}

// Will be [string, number, boolean]
type UserParams = Parameters<typeof createUser>;

const userParams: UserParams = ['Charlie', 30, false];
Enter fullscreen mode Exit fullscreen mode

🧩 Bonus: Combining Utility Types

Utility types are composable! You can mix and match them to fit complex use case. The real power comes from combining these utility types:

interface User {
  id: number;
  name: string;
  email: string;
  role: 'admin' | 'user';
  settings: {
    theme: string;
    notifications: boolean;
  };
}

// Only id and email, both required
type UserCredentials = Required<Pick<User, 'id' | 'email'>>;

// All User properties except id, all optional
type UpdateableUser = Partial<Omit<User, 'id'>>;

// Maps user IDs to roles
type UserRoleMap = Record<number, Extract<User['role'], 'admin'>>;
Enter fullscreen mode Exit fullscreen mode

This gives you a type that includes all of User, except for the id (which is omitted), and makes everything else optional.

✅ Final Thoughts

TypeScript’s utility types let you write less code while making your intent crystal clear. Once you start incorporating them into your workflow, you’ll wonder how you ever lived without them!

💬 What’s your favorite utility type?

Have any cool tricks with Pick, Omit, or Record? Drop them below — let’s learn together! 🚀

Top comments (0)