TypeScript Utility Types
TypeScript utility types are predefined constructs that facilitate common type transformations, enhancing code flexibility and maintainability.
- They allow developers to modify existing types easily, such as by making properties optional or read-only.
- Utility types help in creating more expressive and concise type definitions, reducing redundancy in code.
Here is the list of utility types in TypeScript:
1. Partial<Type>
Partial utility type constructs a type with all properties of the provided type T set to optional. It's useful when we want to create a new type where all properties can be present but aren't required.
Syntax:
Partial<T>
- T- represents the original type whose properties are being made optional.
interface User {
Id: string;
email: string;
}
type PartialUser = Partial<User>;
const partialUser: PartialUser = { Id: '123' };
console.log(partialUser);
- The PartialUser type has all properties of User set to optional.
- The partialUser object is valid with only the id property.
Output:
{ Id: '123' }
2. Required<Type>
In contrast to Partial, Required utility type constructs a type where all properties of the provided type T are set to required. This is useful when we want to ensure that all properties must be present.
Syntax:
Required<T>
- T: represents any type whose properties we want to make required.
interface User {
name?: string;
age?: number;
}
type RequiredUser = Required<User>;
const requiredUser: RequiredUser = { name: 'John', age: 20 };
console.log(requiredUser);
- The RequiredUser type has all properties of User set to required.
- The requiredUser object must include both name and age properties.
Output:
{ name: 'John', age: 20 }
3. Readonly<Type>
Readonly utility type constructs a type where all properties of the provided type T are marked as readonly. It's beneficial for ensuring immutability.
Syntax:
Readonly<T>
interface User {
name: string;
age: number;
}
type ReadonlyUser = Readonly<User>;
const readonlyUser: ReadonlyUser = { name: 'John', age: 30 };
readonlyUser.name = 'Jane';
// This line will giv error: 'name' is read-only
- The ReadonlyUser type has all properties of User set to readonly.
- Attempting to modify readonlyUser.name results in a compile-time error.
Output:
error: Cannot assign to 'name' because it is a read-only property.
4. Pick<Type, Keys>
Pick utility type constructs a type by picking the set of properties specified by the keys K from the type T. It's useful when we want to create a new type by selecting only a few properties from an existing type.
Syntax:
Pick<T, K>
- T: Represents the type from which properties will be picked.
- K: Represents the keys of T that will be picked.
interface User {
name: string;
age: number;
email: string;
}
type UserSummary = Pick<User, 'name' | 'email'>;
const userSummary: UserSummary = { name: 'ram', email: 'ram@example.com' };
console.log(userSummary)
- The UserSummary type includes only the name and email properties from User.
- The userSummary object must include both name and email properties.
Output:
{ name: 'ram', email: 'ram@example.com' }
5. Parameters<Type>
Parameters utility type obtains the parameter types of a function type T as a tuple type. It's beneficial when we need to extract the parameter types of a function for further type manipulation.
Syntax:
Parameters<T>
- T: Represents a function type whose parameters we want to extract.
function sum(a: number, b: number): number {
return a + b;
}
type SumParams = Parameters<typeof sum>;
// SumParams is [number, number]
const params: SumParams = [1, 2];
console.log(params);
- The SumParams type is a tuple representing the parameter types of the sum function.
- The params array is valid with two numbers, matching the sum function's parameters.
Output:
[1, 2]
6. Record<Keys, Type>
Record utility type constructs an object type whose property keys are of type K and values are of type T. It's useful when you want to define a fixed set of keys with specific value types.
Syntax:
Record<K, T>
- K: Represents the keys of the resulting record type.
- T: Represents the type of values associated with the keys.
type Fruit = 'apple' | 'banana' | 'orange';
type Inventory = Record<Fruit, number>;
const inventory: Inventory = {
apple: 10,
banana: 15,
orange: 20
};
console.log(inventory)
- The Inventory type defines an object with keys of type Fruit and values of type number.
- The inventory object correctly maps each fruit to its quantity.
Output:
{ apple: 10, banana: 15, orange: 20 }
7. Exclude<Type, ExcludedUnion>
The Exclude utility type constructs a new type by excluding from T all properties that are assignable to U.
Syntax:
Exclude<T, U>
- T: Represents the original type you want to manipulate.
- U: Represents the subset of T that you want to exclude.
type Status = 'pending' | 'approved' | 'rejected';
type NonRejectedStatus = Exclude<Status, 'rejected'>;
const status: NonRejectedStatus = 'approved';
console.log(status);
- NonRejectedStatus includes only 'pending' and 'approved', excluding 'rejected'.
- Assigning 'rejected' to status would result in an error.
Output:
approved
Best Practices for Using TypeScript Utility Types:
- Understand Each Utility: Familiarize yourself with utility types like Partial, Readonly, Pick, and Omit to use them effectively.
- Maintain Consistency: Apply utility types consistently across your codebase to enhance readability and maintainability.
- Combine Utilities Wisely: Combine utility types to create complex types, but avoid overcomplicating type definitions.