adnenre
#TypeScript

TypeScript Utility

TypeScript Utility Types Guide (Omit, Pick, Partial, Required, Readonly, Record, etc.).

This guide explains TypeScript utility types that manipulate object properties, with real-world examples.


#1 - Omit

Description: Omit<T, K> creates a new type from T excluding keys K. Useful for POST/PUT requests where some properties (like id) are generated by the server.

interface IUser {
  id: number;
  name: string;
  email: string;
}

// ❌ Manually copy type without id
interface INewUser {
  name: string;
  email: string;
}

// ✅ Use Omit
type INewUserGeneric = Omit<IUser, 'id'>;

// Example: creating a new user
const newUser: INewUserGeneric = { name: 'Jhon', email: 'jhon@example.com' };

#2 - Pick

Description: Pick<T, K> creates a type by selecting specific keys K from T. Useful for partial responses or form data.

interface IUser {
  id: number;
  name: string;
  email: string;
}

// ❌ Manual selection
interface IUserNameOnly {
  name: string;
}

// ✅ Use Pick
type IUserNamePick = Pick<IUser, 'name'>;

const userName: IUserNamePick = { name: 'Mery' };

#3 - Partial

Description: Partial<T> makes all properties optional. Useful for PATCH requests or optional fields in forms.

interface IUser {
  id: number;
  name: string;
  email: string;
}

// ❌ Manual optional
interface IUserPatchManual {
  id?: number;
  name?: string;
  email?: string;
}

// ✅ Use Partial
type IUserPatch = Partial<IUser>;

const updateUser: IUserPatch = { name: 'Jhon Updated' };

#4 - Required

Description: Required<T> converts all optional properties to required. Useful for ensuring full data after vjhondation.

interface IUserPatch {
  name?: string;
  email?: string;
}

// ❌ Manually require properties
interface IUserFull {
  name: string;
  email: string;
}

// ✅ Use Required
type IUserFullRequired = Required<IUserPatch>;

const fullUser: IUserFullRequired = { name: 'Jhon', email: 'jhon@example.com' };

#5 - Readonly

Description: Readonly<T> makes all properties immutable. Useful for state management or constants.

interface IUser {
  id: number;
  name: string;
}

// ❌ Mutable object
let user = { id: 1, name: 'Jhon' };
user.id = 2; // allowed ❌

// ✅ Readonly
const readonlyUser: Readonly<IUser> = { id: 1, name: 'Jhon' };
// readonlyUser.id = 2 // ❌ Error: cannot assign to 'id'

#6 - Record

Description: Record<K, T> creates an object type with keys K and values T. Useful for lookup tables or maps.

interface IUser {
  id: number;
  name: string;
}

// ❌ Manual object type
const userMapManual: { [key: string]: IUser } = {
  u1: { id: 1, name: 'Jhon' },
  u2: { id: 2, name: 'Mery' },
};

// ✅ Use Record
type UserMap = Record<string, IUser>;
const userMap: UserMap = {
  u1: { id: 1, name: 'Jhon' },
  u2: { id: 2, name: 'Mery' },
};

#7 - Exclude & Extract

Description: Exclude<T, U> removes types, Extract<T, U> keeps only specified types. Useful for union type filtering.

type Status = 'active' | 'inactive' | 'pending';

// ❌ Manual union exclusion
type ActiveOnlyManual = 'active';

// ✅ Exclude
type ActiveOnly = Exclude<Status, 'inactive' | 'pending'>;

// ✅ Extract
type PendingOnly = Extract<Status, 'pending'>;

const userStatus: ActiveOnly = 'active';
const pending: PendingOnly = 'pending';

#8 - NonNullable

Description: NonNullable<T> removes null and undefined from a type. Useful for sanitized API responses.

type NullableString = string | null | undefined;

// ❌ Manual exclusion
type NotNullManual = string;

// ✅ NonNullable
type NotNull = NonNullable<NullableString>;

const name: NotNull = 'Jhon';

#9 - ReturnType & Parameters

Description: Get the return type or parameter types of a function. Useful for DRY typing.

function getUser() {
  return { id: 1, name: 'Jhon' };
}

// ❌ Manual type
interface IUserManual {
  id: number;
  name: string;
}

// ✅ Use ReturnType
type IUserReturn = ReturnType<typeof getUser>;

const user: IUserReturn = { id: 1, name: 'Jhon' };

// Parameters
function updateUser(id: number, name: string) {}

// ✅ Use Parameters
type UpdateUserParams = Parameters<typeof updateUser>;
const args: UpdateUserParams = [1, 'Mery'];

#10 - Keyof & Index Types

Description: keyof gets all keys of a type. Useful for dynamic key access and constraints.

interface IUser {
  id: number;
  name: string;
  email: string;
}

// ❌ Manual key type
type UserKeyManual = 'id' | 'name' | 'email';

// ✅ keyof
type UserKey = keyof IUser; // 'id' | 'name' | 'email'

function getProp<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}

const user: IUser = { id: 1, name: 'Jhon', email: 'jhon@example.com' };
const userName = getProp(user, 'name'); // "Jhon"

#11 - Note

Utility types enable reusable, concise, and type-safe code:

✅ Using these patterns improves REST API type safety, object manipulation, and reduces manual boilerplate.

Share this post