TypeScript Utility Types You Should Know
SkillVeris Team
Engineering Team

TypeScript utility types are built-in generic helpers that derive a new type from an existing one, so you avoid duplicating type definitions.
In this guide, you'll learn:
- Partial and Required flip every property between optional and mandatory in a single expression.
- Pick and Omit build a smaller type by selecting or removing named properties from a larger one.
- Record<K, V> constructs an object type with known keys and a uniform value type, ideal for lookups and maps.
- ReturnType and Parameters extract the output and input types of a function without you restating them.
1What Are TypeScript Utility Types?
TypeScript utility types are built-in generic types that take an existing type and produce a new one based on it. Instead of hand-writing a second interface that is almost identical to the first, you apply a helper like Partial<User> or Omit<User, 'password'> and let the compiler derive the shape for you.
They matter because real applications have many closely related shapes: the full database record, the version you send to the client, the fields a form can edit, the payload an update accepts. Utility types let all of these descend from one source of truth, so a change in the base type ripples out automatically.
2Partial and Required
Partial<T> makes every property of T optional, while Required<T> makes every property mandatory. Partial is the one you reach for constantly — update functions, patch payloads, and default-merging all deal with objects where only some fields are present.
- type User = { id: number; name: string; email: string }
- type UserUpdate = Partial<User> // all fields optional
- function update(id: number, changes: Partial<User>) { }
- type StrictConfig = Required<Config> // every field must be set
💡Pro Tip
Partial is perfect for a patch endpoint: the caller sends only the fields that changed, and the compiler still guarantees each one matches its original type.
3Pick and Omit
Pick<T, Keys> keeps only the named properties, and Omit<T, Keys> keeps everything except the named ones. They are two sides of the same coin — use whichever expresses your intent with fewer keys listed.
- type PublicUser = Omit<User, 'password'> // hide sensitive fields
- type Credentials = Pick<User, 'email' | 'password'>
- type Preview = Pick<Article, 'title' | 'slug' | 'excerpt'>
Choosing Between Them
Reach for Pick when you want a small subset of a large type, and Omit when you want almost everything minus a field or two. Omit is especially handy for stripping secrets before sending data to the browser.
4Record for Keyed Objects
Record<Keys, Value> builds an object type whose keys come from Keys and whose values all share the Value type. It is the cleanest way to describe lookup tables, dictionaries, and configuration maps where you know the allowed keys up front.
Because the key type can be a union of string literals, the compiler forces you to provide an entry for every key — a small guarantee that prevents forgotten cases in things like status-to-color mappings.
- type Role = 'admin' | 'editor' | 'viewer'
- type Permissions = Record<Role, boolean>
- const access: Permissions = { admin: true, editor: true, viewer: false }
- type Cache = Record<string, User> // open-ended string keys
5ReturnType, Parameters, and Awaited
Some utility types extract information from functions instead of objects. ReturnType<typeof fn> gives you whatever a function returns, Parameters<typeof fn> gives a tuple of its argument types, and Awaited<T> unwraps a Promise to the value inside it.
These shine when a function already encodes the shape you need. Rather than declare a separate return interface and keep it in sync by hand, you derive it directly from the implementation.
- function createUser() { return { id: 1, name: 'Ada' } }
- type NewUser = ReturnType<typeof createUser>
- type Args = Parameters<typeof createUser>
- type Data = Awaited<ReturnType<typeof fetchUser>> // unwrap Promise
6Readonly and NonNullable
Readonly<T> marks every property as read-only so assignments after creation fail at compile time, which is useful for frozen configuration and immutable state. NonNullable<T> removes null and undefined from a type, handy after you have already guarded against them.
- type FrozenConfig = Readonly<Config>
- type Name = NonNullable<string | null | undefined> // string
- const settings: Readonly<Settings> = load()
7Combining Utility Types
Utility types compose, and that is where they become powerful. You can nest them to express precise shapes without ever restating a property, keeping one canonical model as the origin of every derived type.
- type DraftArticle = Partial<Omit<Article, 'id' | 'createdAt'>>
- type ReadonlyPreview = Readonly<Pick<Article, 'title' | 'slug'>>
- type Lookup = Record<string, Pick<User, 'id' | 'name'>>
🔑Single Source of Truth
When every variant descends from one base type, renaming a field or changing its type updates the whole chain automatically — no manual synchronisation.
8Common Mistakes to Avoid
Utility types are forgiving, but a few habits cause confusion or silently weaken your types.
- Reaching for a hand-written duplicate interface when Pick or Omit would keep the two in sync automatically.
- Using Omit with a key name that does not exist on the base type — it compiles silently and hides typos, so double-check spellings.
- Overusing Partial on function arguments, which lets callers omit fields your logic actually requires.
- Forgetting that Record forces every literal key to be present, then being surprised by a missing-property error.
- Deeply nesting utility types until the expression is unreadable — extract intermediate named types instead.
9Key Takeaways
A handful of utility types cover the vast majority of real-world transformations.
- Partial and Required toggle optionality across a whole type.
- Pick and Omit carve a smaller type out of a larger one.
- Record builds keyed object types with a uniform value.
- ReturnType, Parameters, and Awaited derive types straight from functions.
- Compose them to keep one base type as the single source of truth.
10Frequently Asked Questions
Q: Do utility types add any runtime code? A: No. They exist only in the type system and are erased during compilation, so they have zero effect on the JavaScript your program ships or on runtime performance.
Q: What is the difference between Pick and Omit? A: Pick keeps only the properties you name, while Omit keeps everything except the properties you name. Use Pick for a small subset and Omit to remove a few fields from a large type.
Q: Can I create my own utility types? A: Yes. Utility types are just generic types using mapped and conditional type syntax. Once you understand keyof, mapped types, and infer, you can build custom helpers tailored to your codebase.
Q: Why use Record instead of an index signature? A: Record<K, V> lets you constrain the keys to a specific union of literals, so the compiler ensures every allowed key is present. A plain index signature accepts any key of that type without that guarantee.
Related Reading
Get The Print Version
Download a PDF of this article for offline reading.
About the Publisher
SkillVeris Team
Engineering Team
Our engineering writers turn abstract code concepts into hands-on, project-driven learning experiences.
View all postsRelated Posts
Never miss an update
Get the latest tutorials and guides delivered to your inbox.
No spam. Unsubscribe anytime.