learn
TypeScript

Utility types, keyof and typeof

Partial, Pick, Omit, Record and the queries that power them.

Utility types derive new shapes from old ones, so one source interface feeds forms, previews, and API payloads without drift. Interviewers ask you to build Partial from scratch — the pattern matters more than the name.

Real-life situation

A profile form submits only the fields the user touched. Typing the update as Partial<Profile> makes every field optional at once; a preview card takes Pick<Profile, "name" | "bio">. Add a field to Profile and every derived shape follows — no second declaration to forget.

Visual

Utility type transforms
BrowserAPIRealtimeCacheDatabaseShareddurableephemeral

Try it

A profile update form

Checked with TypeScript 6.0.3, strict mode

typescriptTab moves to the next control
interface Profile {
id: number;
name: string;
email: string;
bio: string;
}
function updateProfile(id: number, patch: Partial<Profile>): string {
const keys = Object.keys(patch).join(",");
return "update " + id + ": " + keys;
}
type ProfilePreview = Pick<Profile, "name" | "bio">;
const preview: ProfilePreview = { name: "sam", bio: "dev" };
console.log(updateProfile(1, { name: "jo" }));
console.log(preview.name + " - " + preview.bio);
type NoBio = Omit<Profile, "bio">;
const short: NoBio = { id: 2, name: "al", email: "a@x.com" };
console.log(short.name + " " + short.email);
const bad: ProfilePreview = { name: "zo", bio: "x", email: "z@x.com" };
console.log(bad.name);

Compiler not loaded. Check or Run loads it here (about 9 MB) — nothing downloads until you do.

Runner helpers

sleep(ms) waits; fakeFetch(url) returns deterministic sample data. TypeScript is stripped before running; imports and exports are not available in the sandbox.

Try deleting email from the last object — clean, printing "zo". keyof Profile is the union of its keys, typeof someValue grabs a value's type, and Profile["email"] indexes one field out. Record<string, number>, Required, and ReturnType<typeof fn> round out the daily set — each is one line, each saves a redeclaration.

Will it compile? — decide first, then reveal.

check.ts
interface Settings {
theme: string;
volume: number;
}
const current: Partial<Settings> = {};
console.log(current);

Interview questions

What are TypeScript utility types?basic

Small built-in generics that transform existing types instead of you rewriting them by hand. Partial, Pick, Omit, and Record reshape objects, while ReturnType and Awaited unwrap function results. You pass your type in and get a precise variant out. Learn this toolbox early — reaching for a utility keeps one source of truth instead of duplicating slightly different interfaces across files.

Interviewers also ask

  • Why use a utility instead of writing a second interface?
How does Partial work?basic

Partial<T> makes every property of T optional, so Partial<User> accepts any subset of user fields. It suits update payloads and patch helpers where callers send only what changed. Inside the function, remember each property may now be undefined and guard accordingly. For the reverse — requiring every field — use Required<T>. Keep the base T strict and derive the lenient variant with the utility.

Interviewers also ask

  • What utility does the opposite of Partial?
How do Pick and Omit work?basic

Pick<User, 'name' | 'email'> keeps only the listed properties, while Omit<User, 'password'> drops the listed ones — both produce a new object type without touching User. Use Pick for narrow views like list rows and Omit for safe variants like creation payloads without server-set fields. Prefer them over copying field declarations, so base-type changes propagate automatically to every derived shape.

Interviewers also ask

  • When would you choose Omit over Pick?
How does Record work?basic

Record<Keys, Value> builds an object type with a fixed key set and a uniform value type, like Record<'admin' | 'user', number> for role counts. Every listed key is required and every value is checked. It suits lookup tables, dictionaries with known keys, and mapped config. For open-ended keys you do not know upfront, use an index signature instead — Record shines when the key union is finite and explicit.

Interviewers also ask

  • When is an index signature better than Record?
How does Required work, and when would you use it?intermediate

Required<T> removes every ?, turning all optional properties into required ones. You use it after defaults are applied or validation has run — the point where a previously partial shape is now guaranteed complete. A function that fills missing config can return Required<Config> to prove the result is whole. It keeps the input type lenient while the output type stays strict, with both derived from one definition.

Interviewers also ask

  • What stage of a pipeline suits Required?
How does ReturnType work?intermediate

ReturnType<typeof fn> extracts a function's declared return type, so you name the result without repeating it. If getUser returns Promise<User>, ReturnType<typeof getUser> is that promise type. It keeps callers in sync when the function evolves — change the implementation once and every derived alias follows. Combine it with Awaited to unwrap the promise to User itself.

Interviewers also ask

  • How would you get the awaited result type too?
How do Exclude and Extract work?intermediate

Both filter a union: Exclude<'a' | 'b', 'a'> keeps 'b', while Extract<'a' | 'b', 'a'> keeps 'a'. You use them to derive narrower states from a shared union — public versus internal statuses, for example — without redeclaring members. They operate purely at the type level and emit nothing. When the union grows, the filtered aliases update automatically, which beats maintaining parallel hand-written lists.

Interviewers also ask

  • How do Exclude and Extract differ?
How does Awaited work?intermediate

Awaited<T> unwraps nested promises to the final resolved value, so Awaited<Promise<Promise<User>>> is just User. It mirrors what await actually gives you at runtime. Pair it with ReturnType — Awaited< ReturnType<typeof getUser>> — to name the loaded data type for state and props without duplicating declarations. It is the cleanest way to talk about async results in synchronous type positions.

Interviewers also ask

  • What does Awaited give you that ReturnType alone does not?

Key takeaways

  • Derive shapes (Partial, Pick, Omit) — never redeclare them.
  • keyof lists keys, typeof borrows a type, indexing reads one field.
  • One source interface keeps forms and payloads in sync.

References

On this page