Lesson 7 of 13 · 0 of 1 exercises solved

Utility Types

TypeScript includes built-in utility types such as Partial, Pick and Omit that build new types from existing ones. Using them saves you from writing and maintaining near-duplicate type definitions.

interface User {
  id: number
  name: string
  email: string
  password: string
  createdAt: Date
  role: "user" | "admin"
}

// Partial<T> — all properties become optional
type UserUpdate = Partial<User>
// { id?: number; name?: string; email?: string; ... }

// Required<T> — all optional properties become required
type StrictUser = Required<UserUpdate>

// Readonly<T> — all properties become readonly
type FrozenUser = Readonly<User>

// Pick<T, Keys> — select a subset of properties
type UserPublic = Pick<User, "id" | "name" | "role">
// { id: number; name: string; role: "user" | "admin" }

// Omit<T, Keys> — exclude properties
type UserWithoutPassword = Omit<User, "password">

// Record<Keys, Type> — create an object type with specific keys
type RolePermissions = Record<"user" | "admin", string[]>
const perms: RolePermissions = {
  user:  ["read"],
  admin: ["read", "write", "delete"],
}

// Exclude<T, U> — remove members from union
type NotAdmin = Exclude<"user" | "admin" | "guest", "admin">
// "user" | "guest"

// Extract<T, U> — keep only members assignable to U
type StringOrNumber = Extract<string | number | boolean, string | number>
// string | number
TypeScript (compiler loads on first run)Ctrl+Enter runs
// ReturnType<T> — extract return type of a function
function getUser() {
  return { id: 1, name: "Alice", email: "alice@example.com" }
}
type UserFromFn = ReturnType<typeof getUser>
// { id: number; name: string; email: string }

// Parameters<T> — extract parameter types as tuple
function createPost(title: string, body: string, authorId: number) {}
type CreatePostArgs = Parameters<typeof createPost>
// [string, string, number]

// Awaited<T> — unwrap Promise type
type ResolvedUser = Awaited<Promise<User>>   // User

// NonNullable<T> — remove null and undefined
type DefinitelyString = NonNullable<string | null | undefined>
// string

// Practical example — form handling pattern
type FormValues = Omit<User, "id" | "createdAt">
type FormErrors = Partial<Record<keyof FormValues, string>>

function validateUser(values: FormValues): FormErrors {
  const errors: FormErrors = {}
  if (!values.name)  errors.name  = "Name is required"
  if (!values.email.includes("@")) errors.email = "Invalid email"
  if (values.password.length < 8)  errors.password = "Min 8 characters"
  return errors
}
TypeScript (compiler loads on first run)Ctrl+Enter runs

Practice

Given interface User { id: number; name: ; email: string; role: "admin" | "reader" }, declare UserPreview = Pick<User, "id" | "name">, UserPatch = Partial<Omit<User, "id">>, and write updateUser(user: User, patch: UserPatch): User that returns a new object with the patch applied.

Exercise

Pick, Omit and Partial

3 checks
interface User {
  id: number
  name: string
  email: string
  role: "admin" | "reader"
}

// type UserPreview = ...
// type UserPatch = ...

function updateUser(user, patch) {
  return user
}

const ada = { id: 1, name: "Ada", email: "ada@example.com", role: "reader" }
console.log(updateUser(ada, { role: "admin" }))
 
TypeScript (compiler loads on first run)Ctrl+Enter runs
Output
Press Run to try your code, then Check answer to grade it.
Finished reading?1 exercise still open. You can come back to it later.

Tip: use the ← and → keys to move between lessons.