TypeScript utility types are predefined types that simplify common type transformations. They allow developers to create new types by modifying or selecting properties from existing types.
- Type Transformation: Modify existing types by making properties optional, required, or readonly.
- Type Selection: Create new types by selecting or excluding specific properties.
- Type Reusability: Reduce duplicate type definitions and improve code maintainability.
- Function Type Extraction: Extract parameter types from existing function types.
Partial<Type>
The Partial<Type> utility type constructs a type with all properties of Type set to optional.
Syntax:
Partial<T>- T: Represents the original type whose properties are made optional.
interface User {
id: string;
email: string;
}
type PartialUser = Partial<User>;
const partialUser: PartialUser = {
id: '123'
};
console.log(partialUser);
- PartialUser makes both id and email optional.
- partialUser is valid even though it contains only the id property.
Output:
{ id: '123' }Required<Type>
The Required<Type> utility type constructs a type with all properties of Type set to required. It is the opposite of Partial<Type>.
Syntax:
Required<T>- T: Represents the type whose optional properties are made required.
interface User {
name?: string;
age?: number;
}
type RequiredUser = Required<User>;
const requiredUser: RequiredUser = {
name: 'John',
age: 20
};
console.log(requiredUser);
- RequiredUser makes both name and age required.
- requiredUser must contain both properties.
Output:
{ name: 'John', age: 20 }Readonly<Type>
The Readonly<Type> utility type constructs a type with all properties of Type marked as readonly. This prevents those properties from being reassigned during TypeScript type checking.
Syntax:
Readonly<T>interface User {
name: string;
age: number;
}
type ReadonlyUser = Readonly<User>;
const readonlyUser: ReadonlyUser = {
name: 'John',
age: 30
};
readonlyUser.name = 'Jane';
The last statement produces a compile-time error:
Cannot assign to 'name' because it is a read-only property.- ReadonlyUser makes all properties of User readonly.
- readonlyUser.name cannot be reassigned through this type.
- Readonly<Type> does not make nested objects deeply immutable.
Pick<Type, Keys>
The Pick<Type, Keys> utility type constructs a type by selecting specific properties from Type.
Syntax:
Pick<T, K>- T: Represents the original type.
- K: Represents the properties to select from T.
interface User {
name: string;
age: number;
email: string;
}
type UserSummary = Pick<User, 'name' | 'email'>;
const userSummary: UserSummary = {
name: 'Ryan',
email: 'ryan@example.com'
};
console.log(userSummary);
- UserSummary contains only name and email.
- Both selected properties are required because they are required in the original User type.
Output:
{ name: 'Ryan', email: 'ryan@example.com' }Parameters<Type>
The Parameters<Type> utility type extracts the parameter types of a function type as a tuple.
Syntax:
Parameters<T>- T: Represents a function type whose parameter types are extracted.
function sum(a: number, b: number): number {
return a + b;
}
type SumParams = Parameters<typeof sum>;
const params: SumParams = [1, 2];
console.log(params);
- SumParams becomes [a: number, b: number].
- params must contain two numbers in the same order as the function parameters.
Output:
[1, 2]Record<Keys, Type>
The Record<Keys, Type> utility type constructs an object type whose property keys are Keys and whose property values are Type.
Syntax:
Record<K, T>- K: Represents the keys of the resulting object type.
- T: Represents the type of the values.
type Fruit = 'apple' | 'banana' | 'orange';
type Inventory = Record<Fruit, number>;
const inventory: Inventory = {
apple: 10,
banana: 15,
orange: 20
};
console.log(inventory);
- Inventory requires the keys apple, banana, and orange.
- Each key must have a number value.
Output:
{ apple: 10, banana: 15, orange: 20 }Exclude<UnionType, ExcludedMembers>
The Exclude<UnionType, ExcludedMembers> utility type constructs a type by excluding from a union all members that are assignable to ExcludedMembers. It operates on union members, not object properties.
Syntax:
Exclude<T, U>- T: Represents the original union type.
- U: Represents the union members to exclude.
type Status = 'pending' | 'approved' | 'rejected';
type NonRejectedStatus = Exclude<Status, 'rejected'>;
const status: NonRejectedStatus = 'approved';
console.log(status);
- NonRejectedStatus contains only 'pending' | 'approved'.
- Assigning 'rejected' to status produces a compile-time error.
Output:
approvedOmit<Type, Keys>
The Omit<Type, Keys> utility type constructs a type by selecting all properties from Type except the specified Keys. It is the opposite of Pick<Type, Keys>.
Syntax:
Omit<T, K>- T: Represents the original type.
- K: Represents the properties to remove.
interface User {
name: string;
age: number;
email: string;
}
type UserWithoutAge = Omit<User, 'age'>;
const user: UserWithoutAge = {
name: 'John',
email: 'john@example.com'
};
console.log(user);
- UserWithoutAge contains name and email.
- The age property is excluded.
Output:
{ name: 'John', email: 'john@example.com' }Best Practices for Using TypeScript Utility Types
- Understand Each Utility: Learn how utility types such as Partial, Required, Readonly, Pick, Omit, and Record transform existing types.
- Reuse Existing Types: Use utility types instead of creating duplicate type definitions.
- Combine Utilities Carefully: Combine utility types when necessary, but avoid creating unnecessarily complex type definitions.
- Use Descriptive Type Names: Give meaningful names to types created using utility types.
- Keep Type Definitions Readable: Prefer simple and understandable type transformations.