AV
HomeAboutProjectBlog

© 2026 Ave syah Shina. All rights reserved.

  1. Home
  2. Blog
  3. 12 — Utility Types: Built-in Type Transformers

12 — Utility Types: Built-in Type Transformers

August 13, 20265 min read
Download as Markdown

"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

[2] Microsoft, "Omit<Type, Keys>," TypeScript Handbook, 2024. [Online]. Available: 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

[4] Microsoft, "Exclude<UnionType, ExcludedMembers>," TypeScript Handbook, 2024. [Online]. Available: 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

[6] Microsoft, "Awaited<Type>," TypeScript Handbook, 2024. [Online]. Available: 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

Knowledge check · Question 1 of 5

`Partial<User>` produces a type where…

Comments

Leave a Comment

You must be signed in to comment

0 Comments

No comments yet. Be the first to comment!