TypeScript · Advanced Types

Utility Types

Utility types are ready-made type transformations built into TypeScript. They let you create “a User but every field optional” or “a User without the password” in one line.

Advanced 5 min Lesson 21 of 29Examples target TypeScript 5.x with "strict": true.
Before you start:Genericskeyof and typeof
0/29 in TypeScript
On this page · 5 min · Advanced

Learning objectives#

  • Transform object types with Partial, Required, Readonly
  • Select properties with Pick and Omit
  • Build dictionaries with Record
  • Filter unions with Exclude, Extract and NonNullable
  • Read function types with ReturnType, Parameters and Awaited

Explanation#

Partial<T> makes every property optional (great for update/patch payloads). Required<T> does the opposite. Readonly<T> makes all properties read-only.

Pick<T, "a" | "b"> keeps only those keys; Omit<T, "password"> removes keys.

Record<K, V> builds an object type with keys K and values V: Record<Role, string[]>.

Union filters: Exclude<U, X> removes members, Extract<U, X> keeps matching ones, NonNullable<T> removes null and undefined.

Function helpers: ReturnType<typeof fn>, Parameters<typeof fn>, and Awaited<T> unwraps a Promise type.

Syntax#

TypeScript Illustrative
type UserUpdate = Partial<User>;
type PublicUser = Omit<User, 'password'>;
type Preview = Pick<User, 'id' | 'name'>;

Code example: One model, many derived types#

TypeScriptOne model, many derived types Illustrative
interface User {
  id: number;
  name: string;
  email: string;
  password: string;
  role: 'admin' | 'editor' | 'viewer';
}


type NewUser = Omit<User, 'id'>;                 // for create forms
type UserUpdate = Partial<Omit<User, 'id'>>;     // for PATCH requests
type PublicUser = Omit<User, 'password'>;        // safe to send to the client
type UserPreview = Pick<User, 'id' | 'name'>;    // for lists


type Role = User['role'];
type Permissions = Record<Role, string[]>;
const permissions: Permissions = {
  admin: ['*'],
  editor: ['posts:write'],
  viewer: ['posts:read'],
};                                               // ✗ if any role is missing


type NonAdmin = Exclude<Role, 'admin'>;          // 'editor' | 'viewer'
type MaybeEmail = string | null | undefined;
type Email = NonNullable<MaybeEmail>;            // string


async function fetchUser(id: number): Promise<PublicUser> {
  return { id, name: 'Asha', email: 'a@x.in', role: 'viewer' };
}
type FetchArgs = Parameters<typeof fetchUser>;           // [id: number]
type Fetched = Awaited<ReturnType<typeof fetchUser>>;    // PublicUser


function updateUser(id: number, changes: UserUpdate) { /* … */ }
updateUser(1, { name: 'Asha V' });               // ✓ only what changed
updateUser(1, { id: 9 });                        // ✗ 'id' does not exist in type 'Partial<Omit<User, "id">>'
Expected output
All derived types follow the User interface automatically. updateUser accepts partial changes but rejects changing the id; the Permissions object must list every role.

This example is illustrative. Copy or download it and run it in your own environment; the expected output is shown above.

Step-by-step explanation#

  1. Omit<User, "id"> describes data for creating a user (the database assigns the id).
  2. Partial<Omit<…>> allows sending only changed fields.
  3. PublicUser removes the password before data leaves the server.
  4. Record<Role, string[]> forces a permissions entry for every role.
  5. Exclude and NonNullable filter unions.
  6. Parameters, ReturnType and Awaited read types from an existing function.

Real-world use case#

API layers define one entity type and derive DTOs from it: CreateDto = Omit<T, "id">, UpdateDto = Partial<CreateDto>, ResponseDto = Omit<T, "password">.

Common mistakes#

Copy-pasting near-identical types

Writing a second UserWithoutPassword by hand means two places to update. Derive it with Omit.

Expecting Partial to be deep

Partial only makes top-level properties optional. Nested objects stay required.

Omit with a misspelled key

Omit<User, "pasword"> silently omits nothing. Double-check keys (or use a stricter custom helper).

Best practices#

  • Keep one source model and derive DTOs with utility types
  • Use Record<Union, V> to force exhaustive maps
  • Use Awaited<ReturnType<typeof fn>> instead of re-declaring result types
  • Combine utilities, but name the result for readability

Remember this#

Partial = all optional. Required = all required. Readonly = all frozen.

Pick = keep these. Omit = drop these.

Record<Keys, Value> = a complete lookup table.

Practice exercise#

Your task: Given interface Product { id: number; name: string; price: number; stock: number }, create: ProductForm (no id), ProductPatch (all form fields optional) and StockMap (Record of product name to stock).

Need a hint?
Omit, Partial and Record.
Show solution
TypeScript Illustrative
interface Product { id: number; name: string; price: number; stock: number }


type ProductForm = Omit<Product, 'id'>;
type ProductPatch = Partial<ProductForm>;
type StockMap = Record<Product['name'], Product['stock']>; // Record<string, number>

Mini quiz#

Utility Types quizMultiple choice Question 1 of 3

Which utility removes the password property from User?

Score so far: 0/0

Want more? Practise all TypeScript MCQs · TypeScript interview questions

My notes#

Saved in this browser.

Progress is saved in this browser. Sign in to sync.