Skip to content

Expert · TypeScript basics · topic 46 of 61 · 30 min

Utility types and real-world TypeScript

Explanation

Utility types build new types from existing ones: Partial (all optional), Required, Readonly, Pick and Omit (choose or drop fields), Record (a map type) and ReturnType. as const and satisfies keep literal values precise. In real projects, validate outside data at the boundary and learn to read error messages from the bottom up.

Why utility types?

You often need variations of one type: a User, a User without the password for the browser, a User where every field is optional for an update form. Copying the shape three times means three places to update. Utility types derive the variations automatically, so they stay in sync.

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

type UserUpdate = Partial<User>;                 // every field optional
type PublicUser = Omit<User, 'password'>;        // everything except password
type LoginForm  = Pick<User, 'email' | 'password'>;
type FrozenUser = Readonly<User>;                // no field can be reassigned
type StockByItem = Record<string, number>;       // { [item: string]: number }
type Roles = Record<'admin' | 'staff' | 'guest', boolean>;
UtilityResult
Partial<T>All properties optional
Required<T>All properties required
Readonly<T>All properties readonly
Pick<T, K>Only the properties K
Omit<T, K>All properties except K
Record<K, V>An object with keys K and values V
ReturnType<F>The return type of function type F
Awaited<T>The value inside a Promise

as const and satisfies

typescript
const STATUSES = ['PLACED', 'SHIPPED', 'DELIVERED'] as const;
type Status = (typeof STATUSES)[number];   // 'PLACED' | 'SHIPPED' | 'DELIVERED'

const ROUTES = {
  home: '/',
  orders: '/orders',
} satisfies Record<string, string>;        // checked against the type, but keeps exact keys
ROUTES.orders;   // OK, and ROUTES.ordrs is an error
as const makes literals readonly and exact; satisfies checks a value without widening it.

Validating data at the boundary

Types vanish at run time, so JSON from an API or a form can be anything. The professional pattern is: treat it as unknown, check it with code (or a validation library such as Zod), and only then give it a type. Everything inside your program can then trust the types.

typescript
interface Order { id: string; amount: number }
function isOrder(x: unknown): x is Order {
  return typeof x === 'object' && x !== null
    && typeof (x as Order).id === 'string'
    && typeof (x as Order).amount === 'number';
}
const data: unknown = JSON.parse('{"id":"OD1","amount":499}');
if (isOrder(data)) console.log(data.amount + 1); // 500, fully typed

Reading TypeScript errors

Long errors look scary, but the useful line is usually the LAST one, which names the exact property that does not match. Read from the bottom up, find the property, then compare the expected and actual types.

output
Type '{ id: number; name: string; }' is not assignable to type 'User'.
  Property 'email' is missing in type '{ id: number; name: string; }' but required in type 'User'.
The second line is the real answer: email is missing.
Careful: Using // @ts-ignore or as any to make an error disappear hides the bug instead of fixing it, and the bug comes back at run time. If you must suppress an error, prefer // @ts-expect-error with a comment explaining why, so it fails loudly once the problem is fixed.

When is any acceptable?

While converting an old JavaScript project step by step, in quick experiments, or for a genuinely dynamic value from a poorly typed library, wrapped and checked quickly. Many teams enable a lint rule that warns on any so it is always a conscious choice.

Think of it like this: Utility types are like the photocopier settings at a print shop: "same document, but only pages 2–3" (Pick), "same, but remove the last page" (Omit), "same, but as a draft anyone can edit" (Partial). You never retype the document.
Tip: Generate types instead of writing them when you can: OpenAPI generators for REST APIs, Prisma for databases, and GraphQL code generators all produce TypeScript types from the source of truth.

Need help?

Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.

Try:

Watch the lesson

Utility types and real-world TypeScript · 1/6

Utility types

In this lesson you will build new types from existing ones and see how TypeScript is used in real projects.

Prefer a video by a teacher? Find free videos on “typescript utility types partial pick omit record satisfies” on YouTube ↗

In real life: An edit-profile form

A job portal lets users edit their profile. The update API accepts any subset of fields except id and email. The team types the request body as Partial<Omit<Profile, 'id' | 'email'>>, so the form cannot accidentally send an id change, and adding a new profile field automatically makes it editable.

typescript
interface Profile { id: number; email: string; name: string; city: string; skills: string[] }
type ProfileUpdate = Partial<Omit<Profile, 'id' | 'email'>>;
const change: ProfileUpdate = { city: 'Hyderabad' };      // OK
// const bad: ProfileUpdate = { email: 'x@y.com' };        // Error: email is not allowed

Practice (0/3 done)

Task 1 · Code · Typescript

Write applyUpdate(user: User, update: Partial<User>): User that returns a NEW user with the given fields changed. The original must not change.

Task 2 · Code · Typescript

Write toPublic(user: User): Omit<User, "password"> that returns the user without the password field.

Task 3 · Code · Typescript

Write a type guard isOrder(x: unknown): x is Order for interface Order { id: string; amount: number; items: string[] }, and parseOrders(json: string): Order[] that parses a JSON array and keeps only the valid orders.

Quick quiz

Question 1

1.Which type makes every property optional?

Question 2

2.What is Omit<{ a: 1; b: 2; c: 3 }, 'b'>?

Question 3

3.Where should outside JSON be validated?

Question 4

4.const s = ['a', 'b'] as const; What is the type of s?

Read more (free)

Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.

Which type makes every property optional?

Answer: Partial<T>

Partial adds ? to every property.

What is Omit<{ a: 1; b: 2; c: 3 }, 'b'>?

Answer: { a: 1; c: 3 }

Omit removes the listed keys.

Where should outside JSON be validated?

Answer: At the boundary where it enters the program

Types are erased, so check data when it arrives.

const s = ['a', 'b'] as const; What is the type of s?

Answer: readonly ['a', 'b']

as const makes a readonly tuple of the exact literals.

Which utility type makes every property optional, for an "edit profile" form where any field may change?Related

Answer: Partial

Partial<T> adds ? to every property of T.

From Generics and utility types

let count = 10; What type does TypeScript infer for count?Related

Answer: number

The value 10 is a number, so TypeScript infers number for a let variable.

From Why TypeScript

When does TypeScript report type errors?Related

Answer: Before running, when you compile or in the editor

Type checking happens at compile time.

From Why TypeScript

const input = document.querySelector<HTMLInputElement>("#pin"); What is the type of input?Related

Answer: HTMLInputElement | null

querySelector returns null when nothing matches, so you must check before using it.

From TypeScript in real projects

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

Next steps

  1. This is the last topic of “TypeScript basics”. The module exam comes next.
  2. Module 9 exam: TypeScript basics · 12 questions · 25 min, without help. 5 topics of this module still to finish first.
  3. Then the next module, Functional patterns and testing. 61 topics left in the course before the final exam.

← Previous: Generics