# TypeScript Utility Types: The Built-in Ones You Need, With Examples

TypeScript ships with built-in utility types like Partial, Pick, Omit, Record, ReturnType, Awaited and NoInfer. This guide explains each with a short example, then adds two custom helpers (DeepPartial and Prettify) and the performance trap to avoid.

Tags: typescript, javascript, web-development
Published: 2023-04-14 (updated 2026-10-22)


TypeScript utility types are generic types that ship with the language and transform one type into another. `Partial<User>` makes every property optional, `Pick<User, 'id'>` keeps only some, and `Omit<User, 'password'>` removes some. They save you from rewriting near-duplicate interfaces, and they are the fastest way to keep types in sync with a single source of truth. Here are the ones I use constantly, with examples, and a few custom helpers that fill the gaps.

I originally wrote this in 2023 and have updated it to cover newer additions like `NoInfer`.

## TypeScript Utility Types at a Glance

| Utility type | What it does |
|---|---|
| `Partial<T>` | Makes all properties optional |
| `Required<T>` | Makes all properties required |
| `Readonly<T>` | Makes all properties read-only |
| `Pick<T, K>` | Keeps only the listed keys |
| `Omit<T, K>` | Removes the listed keys |
| `Record<K, V>` | Object type with keys `K` and values `V` |
| `Exclude<U, X>` | Removes members from a union |
| `Extract<U, X>` | Keeps members of a union |
| `NonNullable<T>` | Removes `null` and `undefined` |
| `ReturnType<F>` | The return type of a function |
| `Parameters<F>` | The parameter types of a function as a tuple |
| `Awaited<T>` | The resolved type of a Promise |
| `NoInfer<T>` | Blocks type inference from a position (TypeScript 5.4+) |

## Partial&lt;Type&gt;

`Partial` creates a new type where every property is optional. Use it for update payloads and optional configuration objects, something you see everywhere in [typed ORM layers like Drizzle and Prisma](/blog/drizzle-orm-vs-prisma-2026/).

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

type PartialUser = Partial<User>;
// { id?: number; name?: string; email?: string }
```

`Required<Type>` is the inverse: it removes the `?` from every property.

## Readonly&lt;Type&gt;

`Readonly` marks every property as read-only, so assignments to them are compile errors. It is handy for configuration and state you never want to mutate.

```typescript
interface Config {
  url: string;
  apiKey: string;
}

type ReadonlyConfig = Readonly<Config>;
```

## Pick&lt;Type, Keys&gt;

`Pick` builds a new type by selecting specific properties. Use it to expose only a subset of a large object.

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

type PublicUser = Pick<User, 'id' | 'name' | 'email'>;
```

## Omit&lt;Type, Keys&gt;

`Omit` is the opposite of `Pick`: it excludes properties. It is the one I reach for to strip sensitive fields.

```typescript
type UserWithoutPassword = Omit<User, 'password'>;
```

## Record&lt;Keys, Type&gt;

`Record` creates an object type with a given set of keys and a single value type. It is a clean way to type dictionaries and lookup tables.

```typescript
type Role = 'admin' | 'editor' | 'viewer';

const permissions: Record<Role, string[]> = {
  admin: ['read', 'write', 'delete'],
  editor: ['read', 'write'],
  viewer: ['read'],
};
```

Because the keys are a union, TypeScript errors if you forget a role.

## Exclude, Extract and NonNullable

These three work on unions.

```typescript
type Status = 'idle' | 'loading' | 'error' | 'done';

type Active = Exclude<Status, 'idle'>; // 'loading' | 'error' | 'done'
type Failed = Extract<Status, 'error' | 'timeout'>; // 'error'
type Name = NonNullable<string | null | undefined>; // string
```

## ReturnType and Parameters

`ReturnType` extracts what a function returns. `Parameters` extracts its arguments as a tuple. Both are useful when you want to type something from a function you do not control.

```typescript
function getUser(id: number): { id: number; name: string } {
  return { id, name: 'Alex' };
}

type UserResult = ReturnType<typeof getUser>;
type GetUserArgs = Parameters<typeof getUser>; // [id: number]
```

## Awaited&lt;Type&gt;

`Awaited` unwraps a Promise, including nested ones. Combine it with `ReturnType` to get the resolved value of an async function:

```typescript
async function fetchUser(): Promise<User> {
  // ...
  return {} as User;
}

type FetchedUser = Awaited<ReturnType<typeof fetchUser>>; // User
```

Note that `ReturnType<typeof fetchUser>` alone is `Promise<User>`, not `User`. That is the mistake `Awaited` fixes.

## NoInfer&lt;Type&gt;

`NoInfer` (TypeScript 5.4) stops a parameter from being used to infer a generic. Without it, a default value can widen the type:

```typescript
function createStore<T extends string>(values: T[], initial: NoInfer<T>) {
  return { values, current: initial };
}

createStore(['a', 'b'], 'c'); // error: 'c' is not 'a' | 'b'
```

Without `NoInfer`, TypeScript would infer `T` as `'a' | 'b' | 'c'` and accept the call.

## Custom Utility Types Worth Writing

The built-ins do not cover everything. Two helpers I add to most projects:

```typescript
// Makes every property optional, recursively
type DeepPartial<T> = {
  [K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K];
};

// Flattens intersections so hover tooltips show a readable type
type Prettify<T> = {
  [K in keyof T]: T[K];
} & {};
```

`DeepPartial` is useful for nested config overrides. `Prettify` has no runtime effect. It just makes editor tooltips show one flat object instead of `A & B & C`.

## A Performance Warning

Deeply recursive utility types like `DeepPartial` or `DeepReadonly` that walk an unbounded tree are where much of the large-codebase compile-time pain comes from. Use them on small, well-bounded shapes, and read the [TypeScript performance guide](/blog/typescript-performance-large-codebases-2026/) before they sneak into hot paths. Utility types are erased at runtime, so they cost nothing when the program runs, but they do cost compiler time. If compile time is the bottleneck, [TypeScript 7's Go compiler](/blog/typescript-7-project-corsa-go-compiler-2026/) helps too.

## Frequently Asked

**What are TypeScript utility types?** Built-in generic types such as `Partial`, `Pick`, `Omit` and `Record` that transform existing types, so you do not have to write variants by hand.

**What is the difference between Pick and Omit?** `Pick` keeps the keys you list. `Omit` removes them. Use whichever list is shorter.

**What is the difference between Partial and Required?** `Partial` makes every property optional. `Required` makes every property mandatory.

**How do I get the resolved type of an async function?** Use `Awaited<ReturnType<typeof fn>>`.

**Do utility types affect runtime performance?** No. Types are erased at compile time, though complex recursive types can slow down the compiler.
