TypeScript Utility Types
2024-01-15
TypeScript ships with utility types that transform existing types into new ones. Instead of writing the same type transformations over and over, you can use these five built-ins that handle the common cases.
1. Partial
Makes all properties optional. Perfect for update functions where you only want to change some fields.
interface User {
id: number;
name: string;
email: string;
}
function updateUser(id: number, updates: Partial<User>) {
// Can update any combination of fields
}
updateUser(1, { name: "John" });
updateUser(2, { email: "john@example.com", name: "Jane" });
2. Pick<T, K>
Selects specific properties from a type.
interface Product {
id: number;
name: string;
price: number;
description: string;
category: string;
}
type ProductCard = Pick<Product, 'id' | 'name' | 'price'>;
3. Omit<T, K>
Excludes specific properties from a type.
type CreateProduct = Omit<Product, 'id'>;
function createProduct(product: CreateProduct) {
// id gets generated server-side
return { id: Math.random(), ...product };
}
4. Record<K, T>
Creates an object type with specific keys and consistent value types.
type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';
type RouteHandler = Record<HttpMethod, (req: Request) => Response>;
const userRoutes: RouteHandler = {
GET: (req) => getUserById(req.params.id),
POST: (req) => createUser(req.body),
PUT: (req) => updateUser(req.params.id, req.body),
DELETE: (req) => deleteUser(req.params.id)
};
5. ReturnType
Extracts the return type from a function. Keeps types in sync without duplication.
function fetchUserProfile() {
return {
id: 1,
name: "John",
email: "john@example.com",
preferences: { theme: 'dark', notifications: true }
};
}
type UserProfile = ReturnType<typeof fetchUserProfile>;
function cacheProfile(profile: UserProfile) {
localStorage.setItem('profile', JSON.stringify(profile));
}
These five utility types handle most type transformation needs. They're built into TypeScript, so you can start using them right away without any setup.