---
title: "12 — Utility Types: Built-in Type Transformers"
uid: utility-types
tags: ["conditional-types", "partial", "typescript", "roadmap:typescript", "omit", "pick", "utility-types", "record"]
excerpt: "Utility types are built-in generics that transform one type into a related variation — optional, readonly, picked, omitted, recorded. Functions that operate on types, not values."
date: 2026-08-13T03:27:27+0000
source: https://www.aveshina.my.id/en/blog/utility-types
---

"A grab-bag of helpers to memorize" was my utility-types model, and the list refused to stick. Writing it down reframed them: **utility types are built-in generics that transform one type into a related variation — making its properties optional, readonly, picking a subset, omitting some, mapping it to a record.** [1] They're functions that operate on types instead of values, and once I saw them that way, the list became a small toolkit rather than a vocabulary test.

The motivation is that real code constantly needs *variations* of a base type. A form holds a partial draft of a User (some fields, not all). A config object is a User with the password field omitted. A lookup table maps user IDs to User records. Each of these is a transformation of User, and spelling out every variation by hand is repetitive and error-prone. Utility types express the transformation directly, so the variation stays in sync with the base type automatically.

## Partial<T> and the shape transformers

**Partial<T>** makes every property of T optional [1]. The classic use is a form or update payload where any subset of fields is valid:

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

Its companions round out the set:

- **Required<T>** — the inverse; makes every property required.
- **Readonly<T>** — makes every property readonly, so they can't be reassigned after construction.
- **Pick<T, Keys>** — selects only the specified properties from T.
- **Omit<T, Keys>** — removes the specified properties from T [2].

Pick and Omit are complements — Pick keeps a named subset, Omit drops a named subset, and either can express the other. I reach for Omit<User, "id"> when creating a new user (no id yet), and Pick<User, "id" | "name"> when I only need a slim view.

## Record<Keys, Type>

**Record<K, V>** builds an object type whose keys are K and whose values are V [3]:

```
type UserMap = Record<string, User>;
// an object with string keys and User values
```

This is the clean way to express "a dictionary/lookup." The keys can be a union of specific strings (Record<"a" | "b", number>), which combines beautifully with keyof to build type-safe maps indexed by an entity's valid keys.

## Exclude, Extract, and NonNullable: union operators

These operate on *union* types rather than object shapes:

- **Exclude<Union, Excluded>** — removes members from a union [4]. Exclude<"a" | "b" | "c", "a"> is "b" | "c".
- **Extract<Union, Extracted>** — keeps only the members assignable to a type. Extract<string | number, string> is string.
- **NonNullable<T>** — removes null and undefined from T. NonNullable<string | null> is string.

These are how I filter and refine unions without rewriting them — Exclude drops unwanted cases, Extract picks matching ones, NonNullable strips absence. They read like set operations because that's exactly what they are.

## Function-related utilities

Three utilities operate on function types:

- **Parameters<F>** — extracts a function's parameter types as a tuple.
- **ReturnType<F>** — extracts a function's return type.
- **InstanceType<C>** — extracts the instance type a constructor produces [5].

These matter when I want to derive types from an existing function rather than redeclare them. ReturnType<typeof fetch> gives me the type fetch returns, so if fetch's signature changes, my derived type follows automatically. This "derive, don't redeclare" pattern is what keeps types in sync as a codebase evolves.

## Awaited<T>: unwrapping promises

**Awaited<T>** recursively unwraps a Promise type to the type it resolves to [6]. Awaited<Promise<string>> is string; Awaited<Promise<Promise<number>>> is number (it unwraps nesting). This mirrors what await does at runtime, and it's how async function return types are computed — the compiler uses Awaited internally so that an async function returning Promise<string> is typed as returning Promise<string> to callers, while the resolved value inside is string.

## How they fit together

The unifying idea is that every utility is a *type-level function* — it takes type arguments and returns a transformed type. Reading them as functions (Partial, Pick, Omit) made the list click: each has a clear input and output, and they compose. Omit<Partial<User>, "id"> means "User with all-optional fields and id removed" — a perfectly reasonable update-payload type built from two utilities. The built-ins cover the common transformations; when they don't, the same compositional thinking extends to mapped and conditional types (the next notes).

## How I use this

My defaults: reach for **Partial** for update/patch payloads and form drafts; **Pick/Omit** for views and creation shapes that drop or select fields; **Readonly** for values that shouldn't change after construction; **Record** for dictionaries and lookup tables; **Exclude/Extract/NonNullable** for refining unions; and **Parameters/ReturnType** to derive types from existing functions rather than redeclaring them. The discipline that pays off is never spelling out a variation by hand when a utility expresses it — because the hand-written version drifts the moment the base type changes, and the utility version updates itself.

## References

[1] Microsoft, "Utility Types," TypeScript Handbook, 2024. [Online]. Available: [https://www.typescriptlang.org/docs/handbook/utility-types.html](https://www.typescriptlang.org/docs/handbook/utility-types.html)

[2] Microsoft, "Omit<Type, Keys>," TypeScript Handbook, 2024. [Online]. Available: [https://www.typescriptlang.org/docs/handbook/utility-types.html#omittype-keys](https://www.typescriptlang.org/docs/handbook/utility-types.html#omittype-keys)

[3] Microsoft, "Record<Keys, Type>," TypeScript Handbook, 2024. [Online]. Available: [https://www.typescriptlang.org/docs/handbook/utility-types.html#recordkeys-type](https://www.typescriptlang.org/docs/handbook/utility-types.html#recordkeys-type)

[4] Microsoft, "Exclude<UnionType, ExcludedMembers>," TypeScript Handbook, 2024. [Online]. Available: [https://www.typescriptlang.org/docs/handbook/utility-types.html#excludeuniontype-excludedmembers](https://www.typescriptlang.org/docs/handbook/utility-types.html#excludeuniontype-excludedmembers)

[5] Microsoft, "InstanceType<Type>," TypeScript Handbook, 2024. [Online]. Available: [https://www.typescriptlang.org/docs/handbook/utility-types.html#instancetypetype](https://www.typescriptlang.org/docs/handbook/utility-types.html#instancetypetype)

[6] Microsoft, "Awaited<Type>," TypeScript Handbook, 2024. [Online]. Available: [https://www.typescriptlang.org/docs/handbook/utility-types.html#awaitedtype](https://www.typescriptlang.org/docs/handbook/utility-types.html#awaitedtype)

[7] M. Chenry, "TypeScript Utility Types Guide," 2023. [Online]. Available: [https://camchenry.com/blog/typescript-utility-types](https://camchenry.com/blog/typescript-utility-types)

```quiz
Q: `Partial<User>` produces a type where…
- every property of User is removed
- every property of User is made optional
correct: 1
explain: Partial transforms a type by making all its properties optional. It's the standard tool for update payloads, form drafts, and any case where a subset of fields is valid.

Q: You need a type like User but without the `id` field. Reach for…
- Pick<User, "id">
- Omit<User, "id">
correct: 1
explain: Omit removes the named properties. Pick would keep only "id" (the opposite). For a creation shape with no id yet, Omit<User, "id"> is the right call.

Q: `Record<"a" | "b", number>` describes…
- an object with keys "a" or "b", each holding a number
- a function returning a number
correct: 0
explain: Record<Keys, Type> builds an object type whose keys are the Keys union and whose values are Type. Here it's an object with keys "a" and "b", each a number.

Q: `Exclude<"GET" | "POST" | "DELETE", "DELETE">` evaluates to…
- "GET" | "POST"
- "DELETE"
correct: 0
explain: Exclude removes the members in the second argument from the union. Removing "DELETE" leaves "GET" | "POST".

Q: Why use `ReturnType<typeof fetch>` instead of writing the return type by hand?
- it's faster at runtime
- the derived type stays in sync with fetch automatically if its signature changes
correct: 1
explain: Deriving a type from the source with ReturnType means changes to fetch's signature propagate automatically. Hand-written types drift from the source as it evolves.
```
