If you're just getting started with TypeScript, you've probably encountered types like string, number, or boolean. But as your codebase grows, managing and manipulating complex types becomes essential. That’s where TypeScript Utility Types shine.
These powerful built-in helpers allow you to transform types effortlessly and write more readable, flexible, and maintainable code. In this guide, we’ll explore some of the most useful utility types for everyday development.
1. Partial
The Partial utility makes all properties of a type optional.
type User = {
id: number;
name: string;
};
const updateUser = (id: number, updates: Partial<User>) => {
// updates can have any subset of User's properties
};
✅ Use it when updating resources, form handling, or patching data.
2. Required
The opposite of Partial, Required makes all properties required, even if they were optional.
type User = {
id?: number;
name?: string;
};
type CompleteUser = Required<User>;
✅ Use it when you're sure all properties must be present.
3. Readonly
This utility makes all properties immutable — they cannot be reassigned.
type Todo = {
title: string;
completed: boolean;
};
const todo: Readonly<Todo> = {
title: "Write blog post",
completed: false,
};
// todo.completed = true; ❌ Error: cannot assign to 'completed'
✅ Use it to enforce immutability and reduce side effects.
4. Record<Keys, Type>
Creates a type with a set of properties Keys of type Type.
type Roles = 'admin' | 'user' | 'guest';
type Permissions = Record<Roles, boolean>;
const perms: Permissions = {
admin: true,
user: true,
guest: false,
};
✅ Use it when you need a map-like object with known keys.
5. Omit<Type, Keys>
Constructs a type by removing one or more properties.
type User = {
id: number;
name: string;
password: string;
};
type SafeUser = Omit<User, 'password'>;
✅ Use it when you want to exclude sensitive or unnecessary data.
6. Pick<Type, Keys>
Constructs a type by selecting specific properties.
type User = {
id: number;
name: string;
email: string;
password: string;
};
type PublicUser = Pick<User, 'id' | 'name'>;
✅ Use it when you want only a few properties from a large type.
7. Exclude<UnionType, ExcludedMembers>
Removes types from a union.
type Status = 'pending' | 'success' | 'error';
type NonErrorStatus = Exclude<Status, 'error'>;
// "pending" | "success"
✅ Use it when refining union types.
8. ReturnType
Extracts the return type of a function.
function getUser() {
return {
id: 1,
name: 'Tawanda',
};
}
type User = ReturnType<typeof getUser>;
✅ Use it when you want to infer return types automatically.
9. Parameters
Extracts the parameter types of a function as a tuple.
function createUser(name: string, age: number) {
return { name, age };
}
type Args = Parameters<typeof createUser>;
// [string, number]
✅ Use it to reuse or forward function arguments dynamically.
💡 Bonus Tip: Combine Utility Types
You can combine utility types to create powerful abstractions:
type Config = {
url: string;
timeout?: number;
retries?: number;
};
type ImmutableConfig = Readonly<Required<Config>>;
Final Thoughts
TypeScript utility types might seem intimidating at first, but once you start using them, they become invaluable tools in your developer toolkit. By mastering these helpers, you’ll write better type-safe code, avoid duplication, and reduce bugs.
Whether you're building a form, processing user data, or just trying to keep your types in check, utility types will help you work smarter, not harder.
💬 Have a favorite utility type or a clever way to use one? Drop it in my inbox!
Happy Typing! ✍️
