TypeScript’s utility types are incredibly powerful tools that help you write safer, more readable, and more maintainable code. As a full stack engineer working with React and TypeScript, knowing how and when to use them is a game-changer.
Let’s walk through some of the most useful built-in utility types with real-world examples 👇
🔹 1. Partial<T>
Makes all properties in a type optional.
🧠 Use Case: Updating part of an object (like a PATCH request)
type User = {
id: number;
name: string;
email: string;
};
function updateUser(id: number, updates: Partial<User>) {
// updates can have any subset of User fields
}
✅ Great for scenarios like form updates or partial state changes.
🔹 2. Pick<T, K>
Creates a new type by picking a subset of keys from a type.
🧠 Use Case: Creating lightweight data objects or props
type User = {
id: number;
name: string;
email: string;
isAdmin: boolean;
};
type UserPreview = Pick<User, 'id' | 'name'>;
✅ Useful when passing only essential fields to a component.
🔹 3. Omit<T, K>
The inverse of Pick — removes the specified keys.
type UserWithoutSensitiveInfo = Omit<User, 'email' | 'isAdmin'>;
✅ Ideal when stripping sensitive data before exposing objects (e.g. in APIs).
🔹 4. Record<K, T>
Constructs an object type with keys K and values of type T.
🧠 Use Case: Enforcing strict object key/value structures
type Role = 'admin' | 'user' | 'guest';
const permissions: Record<Role, boolean> = {
admin: true,
user: false,
guest: false,
};
✅ Keeps your objects consistent and type-safe.
🔹 5. Required<T> & Readonly<T>
- Required makes all fields non-optional
- Readonly makes all fields immutable
type Props = {
id?: number;
name: string;
};
type StrictProps = Required<Props>;
type ImmutableProps = Readonly<Props>;
✅ Helpful when enforcing stricter contracts in APIs or configs.
🔹 6. Exclude<T, U> & Extract<T, U>
- Exclude removes types from T that exist in U
- Extract gets the common types between T and U
type Roles = 'admin' | 'user' | 'guest';
type Restricted = Exclude<Roles, 'guest'>; // 'admin' | 'user'
type Visible = Extract<Roles, 'guest' | 'user'>; // 'user' | 'guest'
✅ Super useful when working with union types or role-based logic.
🔹 7. NonNullable<T>
Removes null and undefined from a type.
type MaybeString = string | null | undefined;
type DefiniteString = NonNullable<MaybeString>; // just `string`
✅ Use this when you've already null-checked a value but want TypeScript to stop complaining.
🔹 8. ReturnType<T>
Extracts the return type of a function type.
function fetchUser() {
return { id: 1, name: 'Alice' };
}
// Will be { id: number, name: string }
type User = ReturnType<typeof fetchUser>;
const user: User = {
id: 2,
name: 'Bob'
};
🔹 9. Parameters<T>
Extracts the parameter types of a function type as a tuple.
function createUser(name: string, age: number, isAdmin: boolean) {
// implementation
}
// Will be [string, number, boolean]
type UserParams = Parameters<typeof createUser>;
const userParams: UserParams = ['Charlie', 30, false];
🧩 Bonus: Combining Utility Types
Utility types are composable! You can mix and match them to fit complex use case. The real power comes from combining these utility types:
interface User {
id: number;
name: string;
email: string;
role: 'admin' | 'user';
settings: {
theme: string;
notifications: boolean;
};
}
// Only id and email, both required
type UserCredentials = Required<Pick<User, 'id' | 'email'>>;
// All User properties except id, all optional
type UpdateableUser = Partial<Omit<User, 'id'>>;
// Maps user IDs to roles
type UserRoleMap = Record<number, Extract<User['role'], 'admin'>>;
This gives you a type that includes all of User, except for the id (which is omitted), and makes everything else optional.
✅ Final Thoughts
TypeScript’s utility types let you write less code while making your intent crystal clear. Once you start incorporating them into your workflow, you’ll wonder how you ever lived without them!
💬 What’s your favorite utility type?
Have any cool tricks with Pick, Omit, or Record? Drop them below — let’s learn together! 🚀
Top comments (0)