Skip to main content

Command Palette

Search for a command to run...

TypeScript Utility Types: Partial, Pick, Omit & Record Explained

Published
9 min readView as Markdown

const relatedArticles = [ slug: 'json-formatting-guide', title: 'JSON Formatting Guide', description: 'Format and validate JSON data in your TypeScript projects.' , slug: 'json-schema-validation-guide', title: 'JSON Schema Validation', description: 'Validate API responses with JSON Schema and TypeScript.' , slug: 'web-performance-optimization', title: 'Web Performance Optimization', description: 'Core Web Vitals and TypeScript tree-shaking for faster apps.' , ]

return (

/ Schema.org JSON-LD /

creates a new type by selecting specific properties from T. Omit creates a new type by excluding specific properties from T. They are complementary: Pick is best when you need a few properties from a large type, while Omit is best when you need most properties but want to remove a few. For example, Pick keeps only id and name, while Omit keeps everything except password.', , ,

'@type': 'Question', name: 'When should I use Partial vs Required in TypeScript?', acceptedAnswer: '@type': 'Answer', text: 'Use Partial when you need a type where all properties are optional, such as update functions that accept partial data (updateUser(Partial)). Use Required when you need to ensure all properties are provided, such as config objects with defaults (Required). Partial makes every property optional (?), while Required removes the optional modifier from every property.', , ,

'@type': 'Question', name: 'How do I create custom utility types in TypeScript?', acceptedAnswer: '@type': 'Answer', text: 'Custom utility types are built using mapped types, conditional types, and template literal types. A mapped type iterates over keys of a type and transforms each property. For example, type Readonly = readonly [P in keyof T]: T[P] makes all properties read-only. Conditional types use the syntax T extends U ? X : Y to create types that depend on conditions. Combine these with infer, keyof, and generic constraints to build powerful reusable type transformations.', , , ], ),

/>

/ Breadcrumb Navigation /

Home / Blog / TypeScript Utility Types

/ Article Header /

# TypeScript Utility Types: Partial, Pick, Omit & Record Explained

TypeScript March 7, 2026 11 min read

/ Article Content /

What Are Utility Types?

TypeScript provides a set of built-in generic types that transform existing types into new ones. These utility types eliminate the need to manually redefine types for common patterns like making properties optional, picking a subset of fields, or creating dictionary types. Instead of duplicating type definitions across your codebase, you derive new types from a single source of truth.

This guide covers every commonly used utility type with real-world examples from API development, React components, and data processing. By the end, you will also know how to build your own custom utility types.

Utility Types at a Glance

Utility Type What It Does Common Use Case

'Partial'All properties optionalUpdate functions, form state 'Required'All properties requiredConfig with defaults merged 'Readonly'All properties read-onlyImmutable state, frozen objects 'Pick'Select specific propertiesAPI response subsets 'Omit'Exclude specific propertiesRemove sensitive fields 'Record'Dictionary/map typeLookup tables, grouped data 'Exclude'Remove types from a unionFilter union members 'Extract'Keep types matching a unionNarrow union types 'ReturnType'Extract function return typeInfer types from functions 'NonNullable'Remove null/undefinedEnsure values exist

'Partial: Make Everything Optional'

'Partial' creates a type where every property of T becomes optional. This is the most commonly used utility type, especially for update operations where only some fields change.

`interface User id: string; name: string; email: string; avatar: string; role: 'admin' | 'user';

// Without Partial -- you'd need a separate type: // interface UpdateUser name?: string; email?: string; ...

// With Partial -- derive it automatically: type UpdateUser = Partial; // id?: string; name?: string; email?: string; avatar?: string; role?: 'admin' | 'user'

// Real-world usage: update function async function updateUser(id: string, data: Partial): Promise // Only the provided fields are updated return await db.users.update( where: id , data );

// Usage -- only update what changed await updateUser('user_123', name: 'New Name' ); // OK await updateUser('user_123', email: 'new@example.com' ); // OK await updateUser('user_123', ); // OK (no changes)

// React form state const [formData, setFormData] = useState>();

function handleChange(field: keyof User, value: string) setFormData(prev => ( ...prev, [field]: value )); `

'Pick and Omit: Select or Exclude Properties'

Pick selects specific properties; Omit removes specific properties. They are complementary tools for creating focused type subsets from larger interfaces.

`interface User id: string; name: string; email: string; password: string; createdAt: Date; updatedAt: Date;

// Pick: select only what you need type UserPreview = Pick; // id: string; name: string; avatar: string

// Omit: remove what you don't want type PublicUser = Omit; // id: string; name: string; email: string; createdAt: Date; updatedAt: Date

// API layer: never expose password function getUserProfile(id: string): Promise const user = await db.users.findById(id); const password, ...publicUser = user; // strip password return publicUser;

// Create form: no id or timestamps (server generates those) type CreateUserInput = Omit; // name: string; email: string; password: string

// Combine with Partial for flexible update type UpdateUserInput = Partial>; // name?: string; email?: string; password?: string; updatedAt?: Date

// React component props type UserCardProps = Pick & onClick: () => void; ;`

'Record: Dictionary Types'

'Record' creates a type with keys of type K and values of type V. It is the type-safe way to define dictionaries, lookup tables, and grouped data.

`// Simple dictionary type UserMap = Record; const users: UserMap = 'user_1': id: 'user_1', name: 'Alice', ... , 'user_2': id: 'user_2', name: 'Bob', ... , ;

// Constrained keys with union type type Theme = 'light' | 'dark' | 'auto'; type ThemeConfig = Record;

const themes: ThemeConfig = light: bg: '#ffffff', text: '#1a1a1a', border: '#e5e5e5' , dark: bg: '#0a0a0a', text: '#fafafa', border: '#333333' , auto: bg: 'inherit', text: 'inherit', border: 'inherit' , ;

// HTTP status code descriptions type StatusCode = 200 | 201 | 400 | 401 | 403 | 404 | 500; const statusMessages: Record = 200: 'OK', 201: 'Created', 400: 'Bad Request', 401: 'Unauthorized', 403: 'Forbidden', 404: 'Not Found', 500: 'Internal Server Error', ;

// Grouped data type GroupedByRole = Record; const grouped: GroupedByRole = admin: [adminUser1, adminUser2], user: [user1, user2, user3], ;`

Record types are especially useful when working with JSON data. Format and inspect JSON objects with our JSON Formatter to understand the data shape before defining your Record types.

'Exclude and Extract: Filter Union Types'

`type Status = 'pending' | 'active' | 'suspended' | 'deleted';

// Exclude: remove members from a union type ActiveStatus = Exclude; // 'pending' | 'active'

// Extract: keep only members matching a condition type InactiveStatus = Extract; // 'suspended' | 'deleted'

// Real-world: event system type AppEvent = | type: 'click'; x: number; y: number | type: 'keydown'; key: string | type: 'scroll'; offset: number | type: 'resize'; width: number; height: number ;

// Extract only mouse-related events type MouseEvent = Extract; // type: 'click'; x: number; y: number

// Exclude specific events from handling type NonScrollEvent = Exclude;

// Extract event types as a union of strings type EventType = AppEvent['type']; // 'click' | 'keydown' | 'scroll' | 'resize'`

'ReturnType and Parameters: Infer from Functions'

`// ReturnType: extract a function's return type function createUser(name: string, email: string) return id: crypto.randomUUID(), name, email, createdAt: new Date() ;

type NewUser = ReturnType; // id: string; name: string; email: string; createdAt: Date

// Parameters: extract function parameter types as a tuple type CreateUserParams = Parameters; // [name: string, email: string]

// Real-world: wrapping third-party functions

type FetchResult = ReturnType; type FetchArgs = Parameters;

// Create a wrapper with the same signature function cachedFetch(...args: FetchArgs): FetchResult const cacheKey = JSON.stringify(args); if (cache.has(cacheKey)) return cache.get(cacheKey); const result = fetchData(...args); cache.set(cacheKey, result); return result;

// Awaited: unwrap Promise return types async function getUser(id: string): Promise ...

type UserResult = Awaited>; // User (not Promise)`

Building Custom Utility Types

Once you understand the built-in utilities, you can build your own using mapped types, conditional types, and template literal types. Here are practical custom utilities used in production codebases.

`// DeepPartial: recursively make all properties optional type DeepPartial = [P in keyof T]?: T[P] extends object ? DeepPartial : T[P]; ;

interface Config server: host: string; port: number ; database: url: string; pool: min: number; max: number ;

// All nested properties are optional type PartialConfig = DeepPartial;

// Nullable: make a type nullable type Nullable = T | null;

// PickByType: pick properties that match a specific value type type PickByType = [K in keyof T as T[K] extends ValueType ? K : never]: T[K]; ;

type StringFields = PickByType; // id: string; name: string; email: string

// RequireAtLeastOne: at least one property must be provided type RequireAtLeastOne = [K in keyof T]-?: Required> & Partial>; [keyof T];

type SearchParams = RequireAtLeastOne; // Must provide at least name, email, or id

// StrictOmit: Omit that errors on non-existent keys type StrictOmit = Omit; // StrictOmit -> compile error! // Omit -> silently returns User`

Best Practices

  • Derive, do not duplicate -- use utility types to create variants from a single source type instead of maintaining parallel interfaces that drift apart.
  • Name derived types clearly -- CreateUserInput is better than UserPartialOmitId. The name should describe usage, not implementation.
  • Use Pick for API boundaries -- define exactly which fields an API endpoint accepts or returns. This documents the contract and catches breaking changes.
  • Combine utilities -- 'Partial>' is perfectly valid and reads clearly: "optional fields except id."
  • Prefer Record over index signatures -- 'Record' is more explicit than ' [key: string]: User ' and works better with constrained key types.
  • Do not over-abstract -- complex nested utility types become unreadable. If a type is hard to understand, define it explicitly with an interface.

Frequently Asked Questions

What is the difference between Pick and Omit in TypeScript?

'Pick' creates a new type by selecting specific properties from T. 'Omit' creates a new type by excluding specific properties from T. They are complementary: Pick is best when you need a few properties from a large type, while Omit is best when you need most properties but want to remove a few. For example, 'Pick' keeps only id and name, while 'Omit' keeps everything except password.

When should I use Partial vs Required in TypeScript?

Use 'Partial' when you need a type where all properties are optional, such as update functions that accept partial data. Use 'Required' when you need to ensure all properties are provided, such as config objects after merging with defaults. Partial makes every property optional (?), while Required removes the optional modifier from every property.

How do I create custom utility types in TypeScript?

Custom utility types are built using mapped types, conditional types, and template literal types. A mapped type iterates over keys of a type and transforms each property. For example, 'type Readonly = readonly [P in keyof T]: T[P] ' makes all properties read-only. Conditional types use the syntax T extends U ? X : Y to create types that depend on conditions. Combine these with infer, keyof, and generic constraints to build powerful reusable type transformations.

/ CTA Section /

Format Your TypeScript Data

Working with JSON APIs, configs, or test fixtures in TypeScript? Format, validate, and inspect your JSON data with our free developer tools.

JSON Formatter Hash Generator

/ Related Articles /

relatedArticles.map((article) => (

article.title

article.description

))

)


Originally published on bytepane.com. Visit for free interactive calculators and tools.

More from this blog

R

Brazora

91 posts