🌱BeginnerAdvanced Beginner Types
Utility Types
Partial, Required, Readonly, Pick, Omit, Record, ReturnType, Parameters TypeScript's built-in type transformers.
Overview
TypeScript ships with a library of built-in **utility types** that transform existing types into new ones. Instead of rewriting a type with slight variations, you compose the variant you need from the original.
They are all built from generics and mapped types internally, but you use them like functions: `Partial<User>` creates a copy of `User` where every property is optional; `Readonly<Config>` makes all properties immutable; `Pick<User, "id" | "name">` keeps only the named keys.
Knowing these saves enormous repetition and keeps your types in sync if you change the source type, all derived types update automatically.
Key Points
- •`Partial<T>` all properties optional: `{ a: string }` → `{ a?: string }`
- •`Required<T>` all properties required (opposite of Partial)
- •`Readonly<T>` all properties readonly
- •`Pick<T, K>` keep only listed keys: `Pick<User, "id" | "name">`
- •`Omit<T, K>` drop listed keys: `Omit<User, "password">`
- •`Record<K, V>` object with keys K and values V: `Record<string, number>`
- •`ReturnType<F>` the return type of a function type F
- •`Parameters<F>` tuple of parameter types of function F
- •`NonNullable<T>` remove null and undefined from T
Examples
Partial, Required, Readonly
interface User {
id: number;
name: string;
email: string;
age?: number;
}
// Partial all optional (great for update payloads)
type UserUpdate = Partial<User>;
// { id?: number; name?: string; email?: string; age?: number; }
function updateUser(id: number, changes: Partial<User>): void {
console.log(`Updating user ${id} with:`, changes);
}
updateUser(1, { name: "Alice New" }); // only name
updateUser(2, { email: "x@y.com", age: 25 });
// Required all required (opposite of Partial)
type FullUser = Required<User>;
// { id: number; name: string; email: string; age: number; }
// Readonly immutable
type FrozenUser = Readonly<User>;
const u: FrozenUser = { id: 1, name: "Bob", email: "b@b.com" };
// u.name = "Alice"; // Error: cannot assign to 'name'Pick and Omit shape slicing
interface Product {
id: number;
name: string;
price: number;
cost: number; // internal don't expose
supplierId: number; // internal
}
// Public-facing type expose only what clients need
type PublicProduct = Omit<Product, "cost" | "supplierId">;
// { id: number; name: string; price: number; }
// Summary type pick what's needed for a list
type ProductSummary = Pick<Product, "id" | "name" | "price">;
const product: PublicProduct = { id: 1, name: "Widget", price: 9.99 };
// Record map a set of keys to a value type
type StockMap = Record<number, number>; // productId → quantity
const stock: StockMap = { 1: 50, 2: 30, 3: 0 };
console.log(stock[1]); // 50
// Record with string keys
type RolePermissions = Record<"admin" | "user" | "guest", string[]>;
const perms: RolePermissions = {
admin: ["read","write","delete"],
user: ["read","write"],
guest: ["read"],
};ReturnType, Parameters, NonNullable
function fetchUser(id: number): { id: number; name: string } {
return { id, name: "Alice" };
}
// Extract the return type
type FetchResult = ReturnType<typeof fetchUser>;
// { id: number; name: string }
// Extract the parameter types
type FetchParams = Parameters<typeof fetchUser>;
// [id: number]
// Useful for mocking and testing
function mockFetch(...args: FetchParams): FetchResult {
const [id] = args;
return { id, name: "Mock User" };
}
// NonNullable remove null/undefined
type MaybeString = string | null | undefined;
type JustString = NonNullable<MaybeString>; // string
console.log(mockFetch(42)); // { id: 42, name: "Mock User" }Common Mistakes
- `Partial` makes ALL properties optional, including ones you might want required consider using `Pick` + `Partial` for partial updates of just some fields
- `Readonly` is shallow nested objects are still mutable; use `DeepReadonly<T>` (custom or from a library) for deep immutability
- Confusing `Omit<T, K>` and `Exclude<T, K>` Omit works on object types (removes keys); Exclude works on union types (removes members)
Note
`Partial<T>` is the perfect type for update/patch payloads in REST APIs. Use `Omit<T, "id" | "createdAt">` for create payloads where auto-generated fields aren't needed from the client.
Exercises
Write TypeScript code to solve each exercise. Click Run to compile and execute it right here, then mark as done.
Loading editor…
Completed: 0 / 5 exercises
Knowledge Check
Question 1 of 4