What Are Utility Types?

TypeScript ships with a set of built-in generic types that transform existing types into new ones. Instead of rewriting interfaces from scratch whenever you need a variation, utility types let you derive exactly what you need — keeping your type definitions DRY and expressive.

1. Partial<T>

Makes every property of T optional. Perfect for update payloads where you only want to send changed fields.

interface User { id: number; name: string; email: string; }
function updateUser(id: number, changes: Partial<User>) { ... }

2. Required<T>

The opposite of Partial — makes every property required. Useful when you've received a fully populated object and want to enforce that nothing is missing.

3. Readonly<T>

Marks all properties as read-only, preventing reassignment. Great for configuration objects or Redux state slices where mutation should be a compile-time error.

const config: Readonly<AppConfig> = loadConfig();
config.apiUrl = "..."; // ❌ Error: Cannot assign to 'apiUrl'

4. Pick<T, K>

Creates a new type by selecting a subset of keys from T. Ideal when you only need part of a large interface — for example, a preview card that only needs id, title, and thumbnail from a full Post type.

type PostPreview = Pick<Post, "id" | "title" | "thumbnail">;

5. Omit<T, K>

The inverse of Pick — excludes the specified keys. Use it when you want everything except a few fields, like omitting password before sending a user object to the client.

type SafeUser = Omit<User, "password" | "salt">;

6. Record<K, V>

Constructs an object type whose keys are of type K and values are of type V. Excellent for lookup tables and dictionaries.

type StatusMap = Record<"active" | "inactive" | "banned", string>;
const labels: StatusMap = { active: "Active", inactive: "Inactive", banned: "Banned" };

7. ReturnType<T>

Extracts the return type of a function type. Extremely useful when you want to type a variable as "whatever this function returns" without duplicating the return type definition.

function getUser() { return { id: 1, name: "Kai" }; }
type User = ReturnType<typeof getUser>; // { id: number; name: string }

8. NonNullable<T>

Removes null and undefined from a type. Handy after you've performed a null check and want TypeScript to know the value is definitely present.

type MaybeString = string | null | undefined;
type DefiniteString = NonNullable<MaybeString>; // string

Combining Utility Types

The real power comes from chaining them together:

// A read-only partial pick — for safe, optional updates
type PatchableUser = Readonly<Partial<Pick<User, "name" | "email">>>;

Start by understanding each one individually, then combine them as your type challenges grow in complexity. These eight cover the vast majority of real-world scenarios, so they're worth memorising early in your TypeScript journey.