TypeScript Utility Types
Utility types transform existing types into new types. They are built-in tools for type manipulation.
Overview
interface User {
name: string;
age: number;
email: string;
}
type PartialUser = Partial<User>; // all optional
type UserName = Pick<User, "name">; // { name: string }
type UserWithoutEmail = Omit<User, "email">; // { name: string; age: number }
Partial and Required
Partial makes all properties optional. Required makes them all required:
interface Config {
host: string;
port: number;
}
let partial: Partial<Config> = { host: "localhost" };
let full: Required<Config> = { host: "localhost", port: 8080 };
Tip: Use Partial for update operations where not all properties are provided.
Readonly
Makes all properties readonly:
interface Todo {
title: string;
completed: boolean;
}
let todo: Readonly<Todo> = { title: "Learn TypeScript", completed: false };
// todo.title = "New"; // Error
Pick and Omit
Pick selects specific properties. Omit excludes them:
interface User {
id: string;
name: string;
password: string;
}
type PublicUser = Pick<User, "id" | "name">;
type SafeUser = Omit<User, "password">;
Record
Creates an object type with specific key and value types:
type StatusCounts = Record<string, number>;
let counts: StatusCounts = { pending: 5, approved: 10 };
ReturnType and InstanceType
Extract types from functions and classes:
function fetchData(): { id: number; name: string } {
return { id: 1, name: "John" };
}
type Data = ReturnType<typeof fetchData>;
Remember: You need typeof to get the function type for ReturnType.
Best Practices
- Use utility types for common transformations instead of redefining types
- Combine utilities like
Partial<Pick<T, K>>for specific subsets - Use
Recordfor dictionaries instead of index signatures - Extract types from values with
ReturnTypeandtypeof - Keep utility type chains simple — avoid deep nesting
Common Mistakes
- Forgetting the type parameter:
PartialneedsPartial<T> - Using
PartialwhenRequiredis needed (wrong direction) - Over-nesting utilities makes types hard to read
- Using
Recordwith non-string keys - Not using
typeofwithReturnType