C.W.K.
Stream
Lesson 01 of 05 · published

`Partial<T>` and `Required<T>`

~8 min · utility-types, partial, required, optionality

Level 0Curious
0 XP0/93 lessons0/23 achievements
0/100 XP to next level100 XP to go0% complete
"Partial makes everything optional. Required does the inverse. Both are one-line utilities you'll reach for weekly."

Partial<T> — make every field optional

Partial<User> takes the User type and produces a new type where every field is optional. { id: number; name: string } becomes { id?: number; name?: string }. Useful for update payloads, configuration overrides, optional form state — anywhere the caller might supply only some fields.

The standard library implementation is one line: type Partial<T> = { [K in keyof T]?: T[K] }. A mapped type that loops over T's keys and applies ? to each. The Type Manipulation track covers mapped types in detail; for now, the pattern is enough to recognize.

Required<T> — make every field mandatory

The inverse. Required<Profile> takes a type with optional fields and makes them all required. Useful when receiving a possibly-incomplete object and asserting completeness, or when narrowing a default-laden config to its strict form after applying defaults.

Common use case: update objects

API endpoints often accept partial update payloads. function updateUser(id: number, patch: Partial<User>) is the clean way to type this: the patch may contain any subset of User's fields. Without Partial, you'd write the entire shape with every field optional by hand — error-prone and brittle to schema changes.

Partial and Required are mirror images. When you have a type and want to describe 'a possibly-incomplete version of it,' use Partial. When you have a possibly-incomplete type and want to assert 'now it's complete,' use Required.

Code

Partial and Required side by side·typescript
interface User {
  id: number;
  name: string;
  email: string;
}

// Partial — every field optional.
type UserPatch = Partial<User>;
// { id?: number; name?: string; email?: string }

function updateUser(id: number, patch: UserPatch) {
  // patch may have any subset of fields.
}

updateUser(1, { name: 'Pippa' });               // ✅
updateUser(1, { name: 'Pippa', email: '...' }); // ✅
updateUser(1, {});                              // ✅ — empty is fine

// Required — inverse.
interface Config {
  host?: string;
  port?: number;
  protocol?: 'http' | 'https';
}

type CompleteConfig = Required<Config>;
// { host: string; port: number; protocol: 'http' | 'https' }

function setup(cfg: CompleteConfig) {
  // cfg.host etc. are guaranteed present
}

External links

Exercise

Define interface Settings { theme: 'light' | 'dark'; fontSize: number; locale: string }. Then write a defaults: Settings constant and a merge(defaults: Settings, overrides: Partial<Settings>): Settings function. Confirm the type system catches an attempt to pass an invalid field in overrides.
Hint
merge returns { ...defaults, ...overrides }. The Partial constraint means overrides may have any subset of fields, but if a key isn't in Settings, the compiler complains.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.