---
title: 'Utility Types'
source: 'https://academia.sh/en/courses/typescript/utility-types'
course: TypeScript
language: en
updated: '2026-08-17T18:09:53+00:00'
license: 'CC BY-SA 4.0'
---

# Utility Types

The standard library's ready-made type transforms; field modifiers, picking and omitting fields, building a table, filtering unions, and tools that derive types from signatures.

Most of the transforms written by hand in this topic — a read-only version, an
optional version, filtering a member out of a union — are already available in the
standard library. These are called **utility types**.

All of them are written with the mechanisms built in earlier lessons: mapped types,
conditional types, `keyof`, and `infer`. This lesson covers what each one does, how it
is built, and how it is used to write the derivatives of the measurement model.

## Field Modifiers and Field Selection

The four most commonly used transforms produce four derivatives of the measurement
model in a single line:

```typescript
interface Measurement {
  id: string;
  sensor: string;
  value: number;
  unit: "C" | "Pa" | "%";
  time: number;
}

type MeasurementSummary = Pick<Measurement, "id" | "value" | "unit">;
type MeasurementInput = Omit<Measurement, "id" | "time">;
type MeasurementPatch = Partial<Omit<Measurement, "id">>;
type ArchivedRecord = Readonly<Measurement>;

const summary: MeasurementSummary = { id: "s-01", value: 21.4, unit: "C" };
const input: MeasurementInput = { sensor: "temperature", value: 21.4, unit: "C" };
const patch: MeasurementPatch = { value: 22.1 };
const archived: ArchivedRecord = {
  id: "s-01",
  sensor: "temperature",
  value: 21.4,
  unit: "C",
  time: 1706000000000,
};

console.log(summary.id, input.sensor, patch.value, archived.time);
```

The output is `s-01 temperature 22.1 1706000000000`.

The four types mean the following. `MeasurementSummary` carries the three fields a
listing screen needs. `MeasurementInput` is the fields given when creating a new
record — the id and timestamp are produced by the system. `MeasurementPatch` is a
partial update request; every field except id can be given, and none is required.
`ArchivedRecord` is a record that cannot be changed.

Because all four are computed from the original type, the corresponding derivatives
grow on their own when a new field is added to `Measurement`. Had they been written by
hand, this link would have broken.

Two diagnostics show that the constraints are really enforced:

```typescript
interface Measurement {
  id: string;
  value: number;
  time: number;
}

type MeasurementInput = Omit<Measurement, "id">;
type ArchivedRecord = Readonly<Measurement>;

const input: MeasurementInput = { id: "s-01", value: 21.4, time: 1 };

declare const archived: ArchivedRecord;
archived.value = 22.1;
```

```text
r2.ts(10,35): error TS2353: Object literal may only specify known properties, and 'id' does not exist in type 'MeasurementInput'.
r2.ts(13,10): error TS2540: Cannot assign to 'value' because it is a read-only property.
```

The definitions of these four types are the same ones written by hand in the mapped
types lesson:

| Utility type | Equivalent |
|---|---|
| `Partial<T>` | `{ [A in keyof T]?: T[A] }` |
| `Required<T>` | `{ [A in keyof T]-?: T[A] }` |
| `Readonly<T>` | `{ readonly [A in keyof T]: T[A] }` |
| `Pick<T, A>` | `{ [B in A]: T[B] }` |
| `Record<A, D>` | `{ [B in A]: D }` |

`Omit` is not in this list, because it is built not directly by mapping but by a
composition: `Pick<T, Exclude<keyof T, A>>`. The names to exclude are first removed
from the `keyof T` union, and the remaining names are picked.

## The Checking Difference Between `Omit` and `Pick`

This composition has a result that is easy to miss:

```typescript
interface Measurement {
  id: string;
  value: number;
}

type A = Omit<Measurement, "missingField">;
type B = Pick<Measurement, "missingField">;
```

```text
r3.ts(7,28): error TS2344: Type '"missingField"' does not satisfy the constraint 'keyof Measurement'.
```

The diagnostic comes only for `Pick`. `Omit`'s second parameter is constrained not by
`keyof T` but by any property key; a nonexistent field name is silently ignored, and
the result is the same as `Measurement`.

The maintenance cost of this is: when a field of `Measurement` is renamed, the `Omit`
notations that exclude it silently become ineffective, and the field that should have
been excluded comes back. In `Pick` notations, the compiler gives a diagnostic.

Practical consequence: when the field set is small, `Pick` is preferred. If `Omit` is
needed, a wrapper that tightens the constraint can be written:

```typescript
interface Measurement {
  id: string;
  value: number;
}

type Without<T, A extends keyof T> = Omit<T, A>;

type Safe = Without<Measurement, "id">;
const value: Safe = { value: 21.4 };
console.log(value.value);
```

The output is `21.4`. If the line
`type Wrong = Without<Measurement, "missingField">;` is added at the end of the file,
after a blank line:

```text
r7.ts(12,35): error TS2344: Type '"missingField"' does not satisfy the constraint 'keyof Measurement'.
```

The only difference is putting the `extends keyof T` constraint on the type parameter;
the body still uses `Omit`.

## Union Filters

Three utility types are built on the distribution behavior of conditional types:

```typescript
type Unit = "C" | "Pa" | "%";
type Interval = [min: number, max: number];

type Intervals = Record<Unit, Interval>;
type NumericUnit = Exclude<Unit, "%">;
type PercentUnit = Extract<Unit, "%" | "ppm">;
type DefinedValue = NonNullable<number | null | undefined>;

const intervals: Intervals = {
  C: [-40, 85],
  Pa: [0, 200000],
  "%": [0, 100],
};
const numeric: NumericUnit = "Pa";
const percent: PercentUnit = "%";
const value: DefinedValue = 21.4;

console.log(intervals.C[1], numeric, percent, value);
```

The output is `85 Pa % 21.4`.

Their definitions are one line with conditional types:

- `Exclude<T, U>` — `T extends U ? never : T`
- `Extract<T, U>` — `T extends U ? T : never`
- `NonNullable<T>` — `T & {}`

In the `Extract` example, the value `"ppm"` is not in the `Unit` union and does not
enter the result; it can be thought of as an intersection. `NonNullable` intersects
with the empty object type to filter out the `null` and `undefined` members.

## Deriving Types from Signatures

The last group is built on `infer` and derives a type from an existing function's
signature:

```typescript
interface Measurement {
  id: string;
  value: number;
}

function createMeasurement(id: string, value: number) {
  return { id, value, createdAt: 0 };
}

async function fetchMeasurement(id: string): Promise<Measurement> {
  return { id, value: 21.4 };
}

type CreatedRecord = ReturnType<typeof createMeasurement>;
type CreationArguments = Parameters<typeof createMeasurement>;
type FetchedRecord = Awaited<ReturnType<typeof fetchMeasurement>>;

const record: CreatedRecord = { id: "s-01", value: 21.4, createdAt: 0 };
const args: CreationArguments = ["s-02", 22.1];
const fetched: FetchedRecord = { id: "s-03", value: 23.0 };

console.log(record.createdAt, createMeasurement(...args).id, fetched.value);
```

The output is `0 s-02 23`. If the line
`const wrong: CreationArguments = ["s-04"];` is added at the end of the file, after a
blank line:

```text
r5.ts(24,7): error TS2322: Type '[string]' is not assignable to type '[id: string, value: number]'.
  Source has 1 element(s) but target requires 2.
```

The diagnostic shows that `Parameters`'s result is a named tuple. `ReturnType` gives
the inferred return type of the `createMeasurement` function; `Awaited` takes the type
of the value a promise produces when resolved, introduced in the Asynchronous
JavaScript course, and also unwraps nested promises.

This group's typical use is using a function's return type elsewhere without writing
it by hand. One warning applies: this link is one-directional, and when the function's
body changes, the derived type changes silently along with it. The rule established in
the Type Inference lesson applies here — the type of a boundary exposed outward should
be written, not left to inference.

## Choosing a Utility Type

| Need | Utility type |
|---|---|
| Make all fields optional | `Partial<T>` |
| Make all fields required | `Required<T>` |
| Make all fields read-only | `Readonly<T>` |
| Keep specific fields | `Pick<T, A>` |
| Remove specific fields | `Omit<T, A>` |
| Build a table from a key set | `Record<A, D>` |
| Remove a member from a union | `Exclude<T, U>` |
| Select a member from a union | `Extract<T, U>` |
| Filter out empty values | `NonNullable<T>` |
| Derive a type from a signature | `ReturnType`, `Parameters`, `Awaited` |

Every row in the table rests on a mechanism built in this topic. There is no need to
memorize the utility types; once what they do and how they are built is known, they are
remembered on their own, and a new one can be written when a transform not on the list
is needed.

## Summary

- Utility types are the standard library's ready-made forms of the mapped and
  conditional type mechanisms built in earlier lessons.
- `Pick`, `Omit`, `Partial`, and `Readonly` compute a data model's derivatives from the
  original type; when the model grows, the derivatives grow with it.
- `Omit` does not constrain its second parameter with `keyof T`; a nonexistent field
  name is silently ignored, while `Pick` gives the `TS2344` diagnostic.
- `Exclude`, `Extract`, and `NonNullable` are union filters built on the distribution
  behavior of conditional types.
- `ReturnType`, `Parameters`, and `Awaited` derive types from existing signatures using
  `infer`; the derived type changes silently when the body changes.

## Next Step

Measurement records do not always carry a flat structure: a record can have
sub-records underneath it, a configuration object can have nested sections underneath
it. Transforms applied to the depth of such structures — making every level read-only,
counting nested key paths — require a type to refer to itself. The next lesson covers
recursive types and the limits the compiler places on them.
