typescript has like 20 utility types. you'll use maybe 5 regularly. here they are.
partial
makes everything optional. perfect for update operations.
interface User {
id: string;
name: string;
email: string;
}
// for updates where anything can change
type UpdateUser = Partial<User>;
function updateUser(id: string, data: UpdateUser) {
// data.name might be undefined
// data.email might be undefined
// that's fine
}
use it: update endpoints, patch operations, optional configs.
pick
grab only the fields you need.
interface User {
id: string;
name: string;
email: string;
password: string;
createdAt: Date;
}
// api response without sensitive stuff
type PublicUser = Pick<User, 'id' | 'name' | 'email'>;
use it: api responses, dtos, anywhere you need a subset.
omit
opposite of pick. remove fields.
// same result, different approach
type PublicUser = Omit<User, 'password' | 'createdAt'>;
// for creating users (no id yet)
type CreateUser = Omit<User, 'id' | 'createdAt'>;
use it: removing sensitive fields, create operations.
record
object with known key types.
// simple cache
type Cache = Record<string, unknown>;
// permissions
type Permissions = Record<'read' | 'write' | 'delete', boolean>;
// grouped data
type UsersByRole = Record<'admin' | 'user', User[]>;
use it: caches, maps, grouped data, dictionaries.
returntype
get the return type of a function.
async function getUser(id: string) {
return db.users.findUnique({ where: { id } });
}
// extract the type without redeclaring
type User = Awaited<ReturnType<typeof getUser>>;
use it: when you don't control the function but need its type.
combining them
the real power is combining:
interface User {
id: string;
name: string;
email: string;
password: string;
createdAt: Date;
}
// create: no id, no createdAt
type CreateUser = Omit<User, 'id' | 'createdAt'>;
// update: everything optional except id
type UpdateUser = Partial<Omit<User, 'id'>>;
// response: no password
type UserResponse = Omit<User, 'password'>;
one source of truth. change User, everything updates.
that's it
partial, pick, omit, record, returntype.
there are more utility types. you probably don't need them. these five cover most real-world cases.
don't overcomplicate types. they should help you, not slow you down.