Lesson 7 of 80
Partial, Pick, Omit, and Record aren't special compiler magic — they're ordinary generics built from mapped types, the same tools available to you.
13 min read
Every option explains itself — why the right one is right, and why each wrong one is wrong. Miss one and it comes back later on a spaced-repetition schedule.
Question 1 of 3
Is Partial<T> special compiler behavior, or something you could implement yourself?
Hints without spoilers, and a plain explanation of why a wrong answer was wrong — answered only from this lesson. Free account, no card.
Sign up freeWhat interviewers actually ask about this, and what a strong answer has to cover.
A strong answer covers
Likely follow-ups
Partial<T>, Pick<T, K>, Omit<T, K>, Record<K, V> feel like built-in language features, but they're just generics, defined using mapped types — a way to build a new type by iterating over another type's keys. Nothing about them is hardcoded into the compiler beyond the generics feature you already know.
type Partial<T> = { [K in keyof T]?: T[K] };
Read it like a loop: for every key K in T, keep the same value type T[K], but make it optional (?). That's the entire implementation — it ships in TypeScript's standard library, but you could write it yourself.
interface User {
id: string;
name: string;
email: string;
}
function updateUser(id: string, changes: Partial<User>) {
// changes might have any subset of User's fields — all optional
}
type UserPreview = Pick<User, "id" | "name">;
// { id: string; name: string } — only the picked keys
type UserWithoutEmail = Omit<User, "email">;
// { id: string; name: string } — every key except the omitted one
Pick and Omit are two sides of the same idea — Pick keeps a subset of keys, Omit keeps everything except a subset. Omit<T, K> is itself built from Pick and Exclude internally — another example of a "utility type" being composed from smaller, general pieces.
type User = { id: string; name: string; email: string } — the full shape.
keyof, indexed access (T[K]), and mapped-type modifiers (?, readonly) — not special-cased compiler behavior. Understanding one utility type well is most of the way to understanding all of them.Omit has a well-known historical gotcha: older TypeScript versions didn't error if you passed a key to Omit that doesn't actually exist on T — a typo could silently do nothing instead of failing to compile. Worth knowing even though newer TypeScript has tightened this.Record<K, V> requires K to be a valid index type — string, number, symbol, or a union of literals. Record<string, User> means "every possible string key maps to a User," which is a much looser guarantee than Record<"admin" | "guest", User>, a fixed, known set of keys.Readonly<T> makes only the top level readonly, not deeply — a nested object inside a Readonly<T> value can still have its own properties mutated, unless it's also wrapped."How is Partial<T> implemented?" tests whether utility types are something you've memorized as a fixed list, or something you actually understand as ordinary generics — and understanding the mechanism means you can build your own the moment the standard library doesn't have exactly what you need.