Skip to content

Utility Types: Partial, Pick, Omit, and Record

TypeScript ships a library of utility types — generic type transformations built into the language. They take an existing type and produce a new one with some systematic change: all properties optional, a subset of properties, a property removed, or a record with specific key and value types. You do not import them — they are always available.

Partial<T> makes every property of T optional:

interface HighScore {
score: number;
total: number;
date: string;
}
type PartialHighScore = Partial<HighScore>;
// { score?: number; total?: number; date?: string }

This is useful when you want to update an existing object with only some fields — a patch operation:

function updateHighScore(current: HighScore, patch: Partial<HighScore>): HighScore {
return { ...current, ...patch };
}
updateHighScore(best, { score: 9 }); // only score changes — total and date preserved

Partial<HighScore> accepts any subset of the full interface. The full HighScore is still required in the function’s first parameter — you only need the partial for the update.

The inverse of PartialRequired<T> makes every property required, removing all ? modifiers:

interface FetchOptions {
amount?: number;
difficulty?: Difficulty;
}
type FullOptions = Required<FetchOptions>;
// { amount: number; difficulty: Difficulty }

Useful after you have merged defaults into a partial options object and want to assert that all fields are now present.

Readonly<T> marks every property as readonly:

type ImmutableQuestion = Readonly<TriviaQuestion>;
// All properties become readonly — same effect as adding readonly to each individually

Readonly<T> is the utility type version of the readonly modifier you applied manually in Module 03. It is useful when you want to freeze a type for a specific context without modifying the original interface.

Pick<T, K> produces a type with only the properties named in K:

type QuestionDisplay = Pick<TriviaQuestion, 'question' | 'category'>;
// { question: string; category: string }

This is useful when a component or function only needs a subset of a larger type. Passing TriviaQuestion to something that only reads question and category technically works, but Pick documents the minimal contract precisely:

function renderHeader(q: Pick<TriviaQuestion, 'question' | 'category'>): void {
console.log(`[${q.category}] ${q.question}`);
}

Now renderHeader cannot accidentally access correctAnswer or allAnswers — it only receives the two properties it needs.

Omit<T, K> produces a type with the named properties removed:

type DisplayQuestion = Omit<TriviaQuestion, 'correctAnswer' | 'allAnswers'>;
// { question: string; category: string; difficulty: Difficulty }

Omit is the complement of Pick — use it when it is easier to name what to exclude than what to include. For TriviaQuestion the question has five properties; if you want all but two, Omit is more concise than Pick with three names.

Record<K, V> constructs an object type with keys of type K and values of type V:

type DifficultyCount = Record<Difficulty, number>;
// { easy: number; medium: number; hard: number }
const counts: DifficultyCount = { easy: 0, medium: 0, hard: 0 };

K must be string, number, symbol, or a union of literal types. When K is a union of literals (like Difficulty), TypeScript requires that every key in the union has an entry — missing one is a compile error.

In AceIt you could use Record<Difficulty, number> to track how many questions the player answered correctly at each difficulty level — a natural extension to the QuizEngine class.

Utility types compose — the result of one can be the input of another:

type ReadonlyPartial<T> = Readonly<Partial<T>>;
// All properties optional AND readonly
type PartialQuestion = ReadonlyPartial<TriviaQuestion>;
// { readonly question?: string; readonly category?: string; ... }

In types.ts or a scratch file:

  1. Use Partial<HighScore> as the parameter type in a patchHighScore(current: HighScore, patch: Partial<HighScore>): HighScore function.
  2. Create type QuestionSummary = Pick<TriviaQuestion, 'question' | 'category' | 'difficulty'>. Write a function that accepts QuestionSummary[] and logs each.
  3. Create type AnonymousQuestion = Omit<TriviaQuestion, 'correctAnswer'>. Use it as the type for a “preview” object that hides the answer.
  4. Create type ScoreByDifficulty = Record<Difficulty, number>. Initialize a variable with all three difficulties set to 0. Try adding a fourth key — observe the error.
  • Partial<T> makes all properties optional — useful for patch/update patterns.
  • Required<T> makes all properties required — removes all ? modifiers.
  • Readonly<T> marks all properties readonly — the utility type equivalent of the manual modifier.
  • Pick<T, K> produces a type with only the listed properties — documents the minimal contract.
  • Omit<T, K> produces a type with the listed properties removed — complement of Pick.
  • Record<K, V> constructs an object type with specific key and value types — requires all keys in a literal union.
  • Utility types compose — the output of one can be the input of another.