Tools: TypeScript Utility Types: A Complete Guide

Tools: TypeScript Utility Types: A Complete Guide

Why Utility Types Matter ## Partial<T> ## Required<T> ## Pick<T, K> ## Omit<T, K> ## Record<K, T> ## Practical Example: API Response Types ## Key Takeaways TypeScript's built-in utility types are powerful tools that help you write cleaner, more maintainable code. In this guide, I'll walk through the most commonly used utility types with practical examples from real-world applications. When building large-scale applications like the ones I work on at Expedia Group, type safety isn't just nice to have — it's essential. Utility types help you derive new types from existing ones without duplication. Makes all properties of T optional. This is incredibly useful for update functions. The opposite of Partial — makes all properties required. Creates a type with only the specified properties. Creates a type excluding the specified properties. Creates a type with keys of type K and values of type T. Here's how I combine these utility types in real projects: Mastering these utility types will significantly improve your TypeScript code quality and developer experience. Originally published at umesh-malik.com Templates let you quickly answer FAQs or store snippets for re-use. Are you sure you want to ? It will become hidden in your post, but will still be visible via the comment's permalink. as well , this person and/or CODE_BLOCK: interface User { id: string; name: string; email: string; role: 'admin' | 'user'; } function updateUser(id: string, updates: Partial<User>) { // Only update the fields that were provided } updateUser('123', { name: 'Umesh' }); // Valid! CODE_BLOCK: interface User { id: string; name: string; email: string; role: 'admin' | 'user'; } function updateUser(id: string, updates: Partial<User>) { // Only update the fields that were provided } updateUser('123', { name: 'Umesh' }); // Valid! CODE_BLOCK: interface User { id: string; name: string; email: string; role: 'admin' | 'user'; } function updateUser(id: string, updates: Partial<User>) { // Only update the fields that were provided } updateUser('123', { name: 'Umesh' }); // Valid! COMMAND_BLOCK: interface Config { host?: string; port?: number; debug?: boolean; } const defaultConfig: Required<Config> = { host: 'localhost', port: 3000, debug: false, }; COMMAND_BLOCK: interface Config { host?: string; port?: number; debug?: boolean; } const defaultConfig: Required<Config> = { host: 'localhost', port: 3000, debug: false, }; COMMAND_BLOCK: interface Config { host?: string; port?: number; debug?: boolean; } const defaultConfig: Required<Config> = { host: 'localhost', port: 3000, debug: false, }; CODE_BLOCK: type UserPreview = Pick<User, 'id' | 'name'>; // Equivalent to: // { id: string; name: string } CODE_BLOCK: type UserPreview = Pick<User, 'id' | 'name'>; // Equivalent to: // { id: string; name: string } CODE_BLOCK: type UserPreview = Pick<User, 'id' | 'name'>; // Equivalent to: // { id: string; name: string } CODE_BLOCK: type CreateUserInput = Omit<User, 'id'>; // Everything except id CODE_BLOCK: type CreateUserInput = Omit<User, 'id'>; // Everything except id CODE_BLOCK: type CreateUserInput = Omit<User, 'id'>; // Everything except id CODE_BLOCK: type UserRoles = Record<string, User[]>; const roleMap: UserRoles = { admin: [/* admin users */], editor: [/* editor users */], }; CODE_BLOCK: type UserRoles = Record<string, User[]>; const roleMap: UserRoles = { admin: [/* admin users */], editor: [/* editor users */], }; CODE_BLOCK: type UserRoles = Record<string, User[]>; const roleMap: UserRoles = { admin: [/* admin users */], editor: [/* editor users */], }; COMMAND_BLOCK: interface ApiResponse<T> { data: T; status: number; message: string; } type UserListResponse = ApiResponse<Pick<User, 'id' | 'name' | 'role'>[]>; type UserUpdatePayload = Partial<Omit<User, 'id'>>; COMMAND_BLOCK: interface ApiResponse<T> { data: T; status: number; message: string; } type UserListResponse = ApiResponse<Pick<User, 'id' | 'name' | 'role'>[]>; type UserUpdatePayload = Partial<Omit<User, 'id'>>; COMMAND_BLOCK: interface ApiResponse<T> { data: T; status: number; message: string; } type UserListResponse = ApiResponse<Pick<User, 'id' | 'name' | 'role'>[]>; type UserUpdatePayload = Partial<Omit<User, 'id'>>; - Use Partial for update operations where not all fields are required - Use Pick and Omit to create focused types from larger interfaces - Use Record for dictionary-like structures - Combine utility types for complex transformations - These types are zero-cost at runtime — they only exist during compilation