In TypeScript, utility types simplify code, making it reusable and more maintainable. They transform existing types, preventing redundant code and offering flexibility when working with type structures. Let’s explore some of the most common utility types with examples.
Awaited is used to infer the type of a value that is wrapped in a Promise. It’s particularly helpful when dealing with asynchronous data.
interface User {
name: string;
age: number;
}
type Person = Awaited<Promise<User>>;
Here, Person will resolve to the User type once the promise is fulfilled.
Partial makes all properties of an object type optional. This is useful when you want to work with incomplete versions of objects.
interface Item {
size: number;
shape: string;
height: number;
width: number;
}
let optionalProperties: Partial<Item> = { height: 20, width: 10 };
In this example, optionalProperties can contain any subset of the properties from Item.
Required does the opposite of Partial, ensuring that all properties are present and non-optional.
interface Item {
size: number;
shape: string;
height: number;
width: number;
}
const requiredProperties: Required<Item> = { height: 20, width: 10, size: 5, shape: 'rectangle' };
Now, all properties of Item must be defined.
Pick allows you to create a new type by selecting specific properties from an existing type.
interface Item {
size: number;
shape: string;
height: number;
width: number;
}
const pickedProperties: Pick<Item, 'height' | 'width'> = { height: 20, width: 10 };
Here, we create a new type containing only height and width from Item.
Omit is the inverse of Pick. It creates a new type by excluding specific properties from an existing type.
interface Item {
size: number;
shape: string;
height: number;
width: number;
}
const remainingProperties: Omit<Item, 'height' | 'width'> = { size: 20, shape: 'circle' };
In this case, the height and width properties are excluded from Item.
Parameters creates a tuple type from the parameters of a function.
function createItem(size: number, shape: string) {
return `Shape: ${shape}, Size: ${size}`;
}
const itemProperties: Parameters<typeof createItem> = [20, 'circle'];
// Resulting type: [number, string]
This utility extracts the types of the function parameters, making them reusable elsewhere.
ConstructorParameters works similarly to Parameters, but it’s used for constructors.
class Vehicle {
constructor(model: string, color: string) {}
}
const vehicleProperties: ConstructorParameters<typeof Vehicle> = ['Sedan', 'Red'];
// Resulting type: [string, string]
This extracts the constructor argument types into a tuple.
Exclude removes specified types from a union type.
type Excluded = Exclude<string | number | boolean, boolean>;
// Result: string | number
In this example, boolean is excluded from the union, leaving string | number.
Extract creates a new type by extracting specified types from a union.
type Extracted = Extract<string | number | boolean, boolean>;
// Result: boolean
Here, boolean is extracted from the union.
NonNullable removes null and undefined from a type.
type NonNull = NonNullable<string | number | undefined>;
// Result: string | number
This ensures the type cannot be null or undefined.
ReturnType infers the return type of a function.
function createItem(name: string, shape: string): Record<string, string> {
return {
name,
shape,
};
}
type ItemReturnType = ReturnType<typeof createItem>;
// Resulting type: Record<string, string>
It’s especially useful for inferring the output of complex functions.
By leveraging these TypeScript utility types, you can make your code cleaner and more adaptable to change, reducing redundancy and enhancing type safety.
Lorem ipsum dolor sit amet consectetur adipisicing elit. Tenetur vero esse non molestias eos excepturi, inventore atque cupiditate.