TypeScript brings advanced type features to JavaScript, allowing developers to write more robust and maintainable code. Two important type operators in TypeScript are union types and intersection types. Union types enable you to work with values that can be of multiple types, while intersection types allow you to combine multiple types into a single type. In this article, we’ll explore how to use union types and intersection types effectively in TypeScript.
Understanding Union Types
Union types in TypeScript allow you to define a variable or parameter that can hold values of different types. You can create a union type by using the pipe (|
) symbol between the type options. Let’s look at a simple example:
let myVariable: string | number;
myVariable = "Hello"; // Valid
myVariable = 42; // Valid
myVariable = true; // Error: Type 'boolean' is not assignable to type 'string | number'
In the above example, myVariable
is declared with a union type of string | number
. It can hold values that are either strings or numbers. Assigning a string or a number to myVariable
is valid, but assigning a boolean value results in a type error.
Union types are particularly useful when you need to handle different types of values in a single variable or parameter. You can use type guards or type narrowing techniques to perform different operations based on the actual type of the value.
function printLength(value: string | number) {
if (typeof value === "string") {
console.log(value.length); // Access string-specific property
} else {
console.log(value.toFixed(2)); // Perform number-specific operation
}
}
printLength("Hello"); // Output: 5
printLength(3.14159); // Output: 3.14
In the printLength
function, we use a type guard (typeof value === "string"
) to conditionally access the length
property when the value is a string. Otherwise, we perform a number-specific operation (toFixed(2)
). Union types enable us to handle different scenarios based on the actual type of the value, enhancing code flexibility and safety.
Working with Intersection Types
Intersection types in TypeScript allow you to combine multiple types into a single type that has all the properties and methods of the constituent types. You can create an intersection type by using the ampersand (&
) symbol. Let’s see an example:
type Person = {
name: string;
};
type Employee = {
employeeId: number;
};
type EmployeePerson = Person & Employee;
const employee: EmployeePerson = {
name: "John",
employeeId: 1234
};
In the above example, we define the Person
and Employee
types, representing properties common to a person and an employee, respectively. We then create the EmployeePerson
type by intersecting Person
and Employee
. The resulting type includes all properties (name
and employeeId
) from both types.
Intersection types are useful when you need to combine multiple types to create a new type that possesses all the features of its constituents. This can be especially handy when working with complex objects or when you want to reuse existing types in a composable manner.
function printDetails(person: Person & Employee) {
console.log(`Name: ${person.name}`);
console.log(`Employee ID: ${person.employeeId}`);
}
const john: Person & Employee = {
name: "John",
employeeId: 1234
};
printDetails(john);
In the printDetails
function, we expect an object that has both the `
Person
and Employee
properties. By using the intersection type Person & Employee
, we ensure that the argument passed to printDetails
satisfies this requirement. We can access and utilize all the properties of both types within the function.
Combining Union and Intersection Types
Union and intersection types can be used together to create even more flexible and expressive type definitions. This allows you to handle scenarios where values can have multiple types or objects with combined properties.
type Shape = {
kind: "circle" | "square";
};
type Circle = Shape & {
radius: number;
};
type Square = Shape & {
sideLength: number;
};
function calculateArea(shape: Circle | Square) {
if (shape.kind === "circle") {
console.log(`Area of circle: ${Math.PI * shape.radius ** 2}`);
} else {
console.log(`Area of square: ${shape.sideLength ** 2}`);
}
}
const circle: Circle = {
kind: "circle",
radius: 5
};
const square: Square = {
kind: "square",
sideLength: 10
};
calculateArea(circle); // Output: Area of circle: 78.53981633974483
calculateArea(square); // Output: Area of square: 100
In this example, we define the Shape
type that has a kind
property representing the shape type. We then create the Circle
and Square
types by intersecting Shape
with additional properties specific to each shape. The calculateArea
function accepts a parameter of type Circle
or Square
. We use the union type Circle | Square
to handle both cases, and the intersection type Shape & Circle
and Shape & Square
to narrow down the properties within the function.
Conclusion
Union types and intersection types are powerful features of TypeScript that enable you to handle diverse scenarios in your code. Union types provide flexibility when working with values that can have multiple types, while intersection types allow you to combine multiple types into a single type with all the properties and methods. By leveraging these advanced type operators, you can enhance type safety, improve code expressiveness, and handle complex scenarios with ease. Incorporate union types and intersection types into your TypeScript code to write more robust and maintainable applications.
There we have how to Use Union Types and Intersection Types in TypeScript, if you want more like this be sure to check out some of my other posts!