You’re Using TypeScript Wrong Without These Utilities


TypeScript? Yeah, we all use it daily.
Defining props for a component, typing an API response, making sure no one passes string
where a number
belongs — all good.
But here’s the thing:
What if you only want to use part of a type?
→ You’d probably create a new one, right?What if you want to use the whole type except one field?
→ Yep, another new one.What if you want the type but with everything optional?
→ You guessed it… another type.
Feels like we’re constantly cloning types just to tweak them a little.
What if you didn’t have to create new ones every time?
Sounds nice, right?
That’s where TypeScript Utility Types come in. They’re like shortcuts that let you reuse and transform existing types instead of reinventing them.
Let’s look at the ones I (and probably you) will actually use every day:
Partial
Pick
Omit
Readonly
Record
1. Partial<T>
– When You Don’t Need Everything
Normally, a type forces you to provide all its properties. But in real projects, that’s not always how data flows. For example, when you’re updating a user profile, you might only have one or two fields to update - not the whole object.
That’s where Partial
comes in. It makes every property optional, so you can pass only what you need.
type User = {
id: number;
name: string;
email: string;
isAdmin: boolean;
};
const updateUser = (id: number, data: Partial) => {
// data could be { name: "Alice" } // or { email: "alice@example.com" }
console.log(`Updating user ${id} with data:`, data);
};
You can use Partial
mostly for:
PATCH API requests (where you only send the changed fields)
Form updates (user changes only name, not email)
Optional configs (default values filled in later)
2. Pick<T, K>
– Only Grab What You Need
Sometimes you don’t want the entire object - just a subset. That’s what Pick
does: it extracts only the keys you care about and ignores the rest.
This is super handy for things like UI components. For example, a user card component doesn’t need admin rights, just basic info.
type User = {
id: number;
name: string;
email: string;
isAdmin: boolean;
};
type UserCardProps = Pick<User, "name" | "email">;
const UserCard = ({ name, email }: UserCardProps) => (
<div>
<h2>{name}</h2>
<p>{email}</p>
</div>
);
You can use Pick
when:
Passing props to components (only what’s needed)
Creating lightweight response objects from APIs
Avoiding duplication of types while working with forms or DTOs
3. Omit<T, K>
– Hide What You Don’t Want
Sometimes the opposite problem happens: you want everything except a few fields. That’s where Omit
comes in.
It’s perfect for situations where you don’t want to expose sensitive data (like password
or isAdmin
) in an API response, but still want the rest of the object.
type User = {
id: number;
name: string;
email: string;
password: string;
isAdmin: boolean;
};
type PublicUser = Omit<User, "password" | "isAdmin">;
const getPublicUser = (user: User): PublicUser => {
const { password, isAdmin, ...rest } = user;
return rest;
};
I use Omit
mostly for:
Sanitizing API responses (never send passwords/tokens back)
Building public-facing models from internal data
Avoiding duplication while still maintaining type safety
4. Readonly<T>
– Lock It Down
There are some objects in your app you never want to change after creation - configs, constants, environment settings, etc. Readonly
makes every property immutable, so you can’t accidentally overwrite it.
type Config = {
appName: string;
version: string;
};
const config: Readonly<Config> = {
appName: "MyApp",
version: "1.0.0",
};
config.version = "2.0.0"; // ❌ Error
I use Readonly
for:
Configuration objects (like app settings, API base URLs)
Constants that should never be reassigned
Preventing bugs where devs accidentally overwrite data
5. Record<K, T>
– Build Clean Mappings
Record
is like a type-safe dictionary. It lets you define a set of keys and the type of their values. This makes it great for creating lookup tables, enums with data, or permission maps.
type Role = "admin" | "user" | "guest";
const rolePermissions: Record<Role, string[]> = {
admin: ["read", "write", "delete"],
user: ["read", "write"],
guest: ["read"],
};
💡 I use Record
when:
Defining permissions or role-based access
Building feature flag systems
Creating lookup tables (like country codes → country names)
TL;DR
Instead of constantly creating new types, just to tweak an existing one. TypeScript gives you shortcuts for this:
Partial
→ updates & optional configsPick
→ select exactly what you needOmit
→ exclude sensitive/unwanted fieldsReadonly
→ lock down constantsRecord
→ clean mappings, type-safe dictionaries
Once you start using them, you’ll wonder why you ever copied and pasted whole types before.
If you enjoyed this article and want to discover more such lesser-known but powerful JavaScript, TypeScript, ReactJS, NextJS features, follow me for more insights.
LinkedIn
Twitter
Subscribe to my newsletter
Read articles from Jiya Agrawal directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
