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>
Section titled “Partial<T>”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 preservedPartial<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.
Required<T>
Section titled “Required<T>”The inverse of Partial — Required<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>
Section titled “Readonly<T>”Readonly<T> marks every property as readonly:
type ImmutableQuestion = Readonly<TriviaQuestion>;// All properties become readonly — same effect as adding readonly to each individuallyReadonly<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>
Section titled “Pick<T, K>”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>
Section titled “Omit<T, K>”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>
Section titled “Record<K, V>”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.
Combining utility types
Section titled “Combining utility types”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; ... }Exercise
Section titled “Exercise”In types.ts or a scratch file:
- Use
Partial<HighScore>as the parameter type in apatchHighScore(current: HighScore, patch: Partial<HighScore>): HighScorefunction. - Create
type QuestionSummary = Pick<TriviaQuestion, 'question' | 'category' | 'difficulty'>. Write a function that acceptsQuestionSummary[]and logs each. - Create
type AnonymousQuestion = Omit<TriviaQuestion, 'correctAnswer'>. Use it as the type for a “preview” object that hides the answer. - Create
type ScoreByDifficulty = Record<Difficulty, number>. Initialize a variable with all three difficulties set to0. 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 propertiesreadonly— 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 ofPick.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.