gonna be honest, I used to ignore TypeScript utility types and just write interfaces from scratch. turns out I was wasting hours. here's the ones I actually use irl.
Pick and Omit
// Pick - only keep specific keys
interface User {
id: string;
name: string;
email: string;
password: string;
createdAt: Date;
}
type UserPreview = Pick<User, 'id' | 'name' | 'email'>;
// { id: string; name: string; email: string; }
// Omit - remove specific keys (password lol)
type PublicUser = Omit<User, 'password'>;
// { id: string; name: string; email: string; createdAt: Date; }
used this ALL the time when passing data to components that don't need everything.
Partial and Required
// Partial - make all properties optional
type UpdateUser = Partial<User>;
// all properties optional - great for PATCH requests
// Required - make all properties required
type CompleteUser = Required<User>;
// opposite of Partial
Record
// quick object type
type UserRoles = Record<string, User>;
type Status = Record<'pending' | 'success' | 'error', boolean>;
instead of writing { [key: string]: User } everywhere.
Exclude and Extract
type AllStatuses = 'pending' | 'success' | 'error' | 'loading';
type RealStatuses = Exclude<AllStatuses, 'loading'>;
// 'pending' | 'success' | 'error'
type MaybeUser = User | null | undefined;
type ActualUser = Extract<MaybeUser, User>;
// User only - removes null and undefined
ReturnType
function createUser() {
return { id: '1', name: 'Ega', email: 'ega@example.com' };
}
type User = ReturnType<typeof createUser>;
// { id: string; name: string; email: string; }
super useful for getting types from factory functions.
Parameters
function doSomething(id: string, options: { verbose: boolean }) {}
// get the parameter types
type DoSomethingParams = Parameters<typeof doSomething>;
// [id: string, options: { verbose: boolean }]
NonNullable
type MaybeName = string | null | undefined;
type DefinitelyName = NonNullable<MaybeName>;
// string - removes null and undefined
Template Literal Types (this one is fun)
type Direction = 'top' | 'bottom' | 'left' | 'right';
type EventName = `on${Capitalize<Direction>}`;
// 'onTop' | 'onBottom' | 'onLeft' | 'onRight'
Practical Example from My Code
// from real project - Kopico community
interface CommunityMember {
id: string;
username: string;
email: string;
role: 'admin' | 'moderator' | 'member';
joinedAt: Date;
}
// for public profile (no email)
type PublicMember = Omit<CommunityMember, 'email'>;
// for admin dashboard (only role and id)
type MemberSummary = Pick<CommunityMember, 'id' | 'username' | 'role'>;
// for updating profile
type UpdateMember = Partial<Omit<CommunityMember, 'id' | 'joinedAt'>>;
My Cheatsheet Order of Use
Pick/Omit- most commonPartial- for updates/optional fieldsRecord- for maps/dictionariesReturnType- for function typesExclude/Extract- for filtering unionsNonNullable- for removing null/undefined
Pro Tip
combine them:
type PublicMemberSummary = Pick<NonNullable<PublicMember>, 'id' | 'username'>;
read it inside out: NonNullable first, then Pick.
these aren't even all of them. there's like 20+ more. but I use maybe 5-6 daily and that's enough tbh.