TypeScript provides built-in utility types that transform existing types.
Partial
Makes all properties optional.
interface User {
name: string;
age: number;
email: string;
}
type PartialUser = Partial<User>;
// { name?: string; age?: number; email?: string; }
function updateUser(user: User, updates: Partial<User>): User {
return { ...user, ...updates };
}
Required
Makes all properties required.
interface Config {
apiUrl?: string;
timeout?: number;
}
type RequiredConfig = Required<Config>;
// { apiUrl: string; timeout: number; }
Readonly
Makes all properties readonly.
interface Point {
x: number;
y: number;
}
type ReadonlyPoint = Readonly<Point>;
// { readonly x: number; readonly y: number; }
const point: ReadonlyPoint = { x: 10, y: 20 };
// point.x = 30; // ❌ Error
Pick
Select specific properties from a type.
interface User {
id: number;
name: string;
email: string;
age: number;
}
type UserPreview = Pick<User, "name" | "email">;
// { name: string; email: string; }
Omit
Remove specific properties from a type.
interface User {
id: number;
name: string;
email: string;
password: string;
}
type PublicUser = Omit<User, "password">;
// { id: number; name: string; email: string; }
Record
Create an object type with specific keys and values.
type UserRoles = Record<string, boolean>;
// { [key: string]: boolean; }
const roles: UserRoles = {
admin: true,
user: false,
guest: false
};
// With specific keys
type Status = "pending" | "approved" | "rejected";
type StatusMap = Record<Status, number>;
// { pending: number; approved: number; rejected: number; }
Exclude
Exclude types from a union.
type T0 = Exclude<"a" | "b" | "c", "a">;
// "b" | "c"
type T1 = Exclude<string | number | (() => void), Function>;
// string | number
Extract
Extract types from a union.
type T0 = Extract<"a" | "b" | "c", "a" | "f">;
// "a"
type T1 = Extract<string | number | (() => void), Function>;
// () => void
NonNullable
Remove null and undefined from a type.
type T0 = NonNullable<string | number | undefined>;
// string | number
type T1 = NonNullable<string[] | null | undefined>;
// string[]
ReturnType
Get the return type of a function.
function getUser() {
return { name: "Alice", age: 25 };
}
type User = ReturnType<typeof getUser>;
// { name: string; age: number; }
Parameters
Get the parameters of a function as a tuple.
function createUser(name: string, age: number, email: string) {
// ...
}
type CreateUserParams = Parameters<typeof createUser>;
// [string, number, string]
InstanceType
Get the instance type of a constructor.
class User {
constructor(public name: string) {}
}
type UserInstance = InstanceType<typeof User>;
// User
Awaited
Get the type that a Promise resolves to (TypeScript 4.5+).
async function getUser() {
return { name: "Alice", age: 25 };
}
type User = Awaited<ReturnType<typeof getUser>>;
// { name: string; age: number; }
Combining Utility Types
interface User {
id: number;
name: string;
email: string;
password: string;
createdAt: Date;
}
// Create a type for user updates (all optional, no password, no id, no createdAt)
type UserUpdate = Partial<Omit<User, "id" | "password" | "createdAt">>;
// { name?: string; email?: string; }
// Create a public user view (no password)
type PublicUser = Omit<User, "password">;
// { id: number; name: string; email: string; createdAt: Date; }
Exercises
Exercise 1: Partial and Required
// Create an interface 'Product' with required properties
// Create a type for product updates using Partial
// Create a type for complete product using Required
Exercise 2: Pick and Omit
// Create an interface 'User' with many properties
// Use Pick to create a 'UserSummary' with only name and email
// Use Omit to create a 'PublicUser' without sensitive data
Exercise 3: Record
// Create a Record type for a translation dictionary
// Keys: "en" | "fr" | "es"
// Values: { hello: string; goodbye: string }
Exercise 4: Exclude and Extract
// Create a union type of HTTP methods
// Use Exclude to remove unsafe methods
// Use Extract to get only safe methods
Exercise 5: Combining Utilities
// Create a complex type transformation:
// - Start with a User interface
// - Make all properties optional
// - Remove 'id' and 'createdAt'
// - Make 'email' required again
Best Practices
- Use Partial for updates - When you want to update some properties
- Use Pick/Omit for views - When you need a subset of properties
- Use Record for dictionaries - When you have key-value mappings
- Combine utilities - Chain them for complex transformations
- Document complex types - Add comments explaining the transformation
Common Mistakes
- Using Partial when you need specific properties
// ❌ Too permissive
type Update = Partial<User>;
// ✅ Better - only allow specific fields
type Update = Partial<Pick<User, "name" | "email">>;
- Not understanding Exclude/Extract
// Exclude removes from union
type T = Exclude<"a" | "b" | "c", "a">; // "b" | "c"
// Extract keeps from union
type T = Extract<"a" | "b" | "c", "a" | "x">; // "a"
- Forgetting ReturnType needs typeof
// ❌ Wrong
type T = ReturnType<getUser>;
// ✅ Correct
type T = ReturnType<typeof getUser>;
Next Steps
Learn about Advanced Types.