TypeScript Utility Types
Utility types are built-in generic types that transform existing types into new ones. Instead of rewriting a type from scratch every time a variation is needed, utility types apply a transformation — making all properties optional, readonly, required, or picking only a subset of properties. They ship with TypeScript and require no installation.
Why Utility Types?
Original Type: +-----------+-----------+ | User | |-----------+-----------| | id | number | required | name | string | required | email | string | required | password | string | required +-----------+-----------+ Partial<User> — all optional (for update operations): +-----------+-----------+ | id? | number | optional | name? | string | optional | email? | string | optional | password? | string | optional +-----------+-----------+ Pick<User, "id" | "name"> — only selected fields: +-----------+-----------+ | id | number | required | name | string | required +-----------+-----------+
Base Type for Examples
interface User {
id: number;
name: string;
email: string;
password: string;
age: number;
isAdmin: boolean;
}
Partial<T>
Makes all properties of a type optional. Useful for update payloads where only a few fields change at a time.
type PartialUser = Partial<User>;
// All properties become optional (?)
function updateUser(id: number, changes: Partial<User>): void {
console.log("Updating user " + id + " with: ", changes);
}
updateUser(1, { name: "Rekha Sharma" }); // Only name — valid
updateUser(2, { email: "new@mail.com", age: 30 }); // Only email and age — valid
updateUser(3, {}); // Empty object — valid (all fields optional)
Required<T>
Makes all properties required — the opposite of Partial. Useful when an optional type must be fully filled before saving.
interface DraftCourse {
title?: string;
description?: string;
price?: number;
level?: string;
}
// Force all fields to be provided before publishing
type PublishedCourse = Required<DraftCourse>;
let course: PublishedCourse = {
title: "TypeScript Mastery",
description: "Complete TypeScript guide",
price: 999,
level: "Beginner"
// All fields required — missing any causes error
};
Readonly<T>
Makes all properties readonly. Once the object is created, no property can be changed. Ideal for configuration objects and constants.
type ReadonlyUser = Readonly<User>;
let adminUser: Readonly<User> = {
id: 1,
name: "Suresh Admin",
email: "suresh@estudy247.com",
password: "hashed_pass",
age: 35,
isAdmin: true
};
adminUser.name = "Changed"; // Error: Cannot assign to 'name' (read-only)
adminUser.age = 36; // Error: Cannot assign to 'age' (read-only)
Pick<T, K>
Creates a new type with only the selected properties from the original type. Useful for creating trimmed-down versions for display or API responses.
// Public profile — only name and email exposed
type PublicProfile = Pick<User, "id" | "name" | "email">;
let profile: PublicProfile = {
id: 5,
name: "Tara Mehta",
email: "tara@mail.com"
// password, age, isAdmin — NOT included
};
console.log(profile.name); // Tara Mehta
console.log(profile.password); // Error: 'password' does not exist on type 'PublicProfile'
Omit<T, K>
Creates a new type by removing specific properties from the original. The inverse of Pick.
// Remove password before sending user data to the client
type SafeUser = Omit<User, "password">;
function getPublicUser(user: User): SafeUser {
let { password, ...safeData } = user;
return safeData;
}
let fullUser: User = { id: 3, name: "Vimal", email: "v@mail.com", password: "secret", age: 28, isAdmin: false };
let publicUser = getPublicUser(fullUser);
console.log(publicUser.name); // Vimal
console.log(publicUser.password); // Error: 'password' does not exist on type 'SafeUser'
Record<K, V>
Creates an object type where all keys are of type K and all values are of type V. Perfect for dictionaries, lookup tables, and maps.
// Map course IDs to course names
type CourseCatalog = Record<number, string>;
let catalog: CourseCatalog = {
1001: "TypeScript Basics",
1002: "React Fundamentals",
1003: "Node.js Backend"
};
console.log(catalog[1001]); // TypeScript Basics
console.log(catalog[1003]); // Node.js Backend
// Map role names to permission arrays
type RolePermissions = Record<"admin" | "instructor" | "student", string[]>;
let permissions: RolePermissions = {
admin: ["read", "write", "delete", "manage"],
instructor: ["read", "write", "create-course"],
student: ["read", "enroll"]
};
Exclude<T, U>
Removes specific members from a union type.
type AllRoles = "admin" | "instructor" | "student" | "guest"; // Remove "guest" from the union type AuthenticatedRoles = Exclude<AllRoles, "guest">; // Result: "admin" | "instructor" | "student" let role: AuthenticatedRoles = "student"; // Valid let role2: AuthenticatedRoles = "guest"; // Error
Extract<T, U>
Keeps only the members that exist in both types — the opposite of Exclude.
type A = "a" | "b" | "c" | "d"; type B = "b" | "d" | "f"; type Common = Extract<A, B>; // Result: "b" | "d" (only common members)
NonNullable<T>
Removes null and undefined from a type.
type MaybeString = string | null | undefined;
type DefiniteString = NonNullable<MaybeString>;
// Result: string
function processName(name: NonNullable<string | null>): string {
return name.toUpperCase(); // Safe — null excluded
}
ReturnType<T>
Extracts the return type of a function type.
function getStudent() {
return { id: 1, name: "Arjun", grade: "A" };
}
type StudentData = ReturnType<typeof getStudent>;
// { id: number; name: string; grade: string; }
let data: StudentData = getStudent();
console.log(data.name); // Arjun
Parameters<T>
Extracts the parameter types of a function as a tuple.
function createOrder(productId: number, quantity: number, address: string): void {
console.log("Order placed");
}
type OrderParams = Parameters<typeof createOrder>;
// [productId: number, quantity: number, address: string]
let args: OrderParams = [1001, 2, "12 MG Road, Bengaluru"];
createOrder(...args); // Order placed
Utility Types Quick Reference
| Utility Type | What It Does | Common Use Case |
|---|---|---|
Partial<T> | All properties optional | PATCH / update operations |
Required<T> | All properties required | Final submission validation |
Readonly<T> | All properties readonly | Immutable config, constants |
Pick<T, K> | Keep only listed properties | Public profile, API response |
Omit<T, K> | Remove listed properties | Strip passwords, sensitive data |
Record<K, V> | Object with typed keys and values | Lookup tables, dictionaries |
Exclude<T, U> | Remove union members | Filter out roles or statuses |
Extract<T, U> | Keep common union members | Shared role permissions |
NonNullable<T> | Remove null and undefined | Safe value assertions |
ReturnType<T> | Get function's return type | Type output of factory functions |
Parameters<T> | Get function's parameter types | Forward function arguments |
Practical Example — Course Platform
interface CourseDetails {
courseId: number;
title: string;
instructor: string;
description: string;
price: number;
isPublished: boolean;
secretNotes: string;
}
// For the admin dashboard — full details
type AdminView = CourseDetails;
// For the public listing — no secret notes, no internal ID
type PublicCourse = Omit<CourseDetails, "secretNotes">;
// For the update API — allow partial updates
type CourseUpdate = Partial<Omit<CourseDetails, "courseId">>;
// For a read-only snapshot
type CourseSnapshot = Readonly<PublicCourse>;
// Lookup table for multiple courses
type CourseLookup = Record<number, PublicCourse>;
function updateCourse(id: number, changes: CourseUpdate): void {
console.log("Updating course " + id);
console.log(changes);
}
// Only update title and price — valid
updateCourse(1001, { title: "TypeScript Complete", price: 1299 });
// Create a lookup
let courseLookup: CourseLookup = {
1001: {
courseId: 1001,
title: "TypeScript Mastery",
instructor: "Anand Rao",
description: "Full TypeScript course",
price: 999,
isPublished: true
}
};
console.log(courseLookup[1001].title); // TypeScript Mastery
