Union and intersection types in TypeScript

TypeScript introduces powerful type features that help developers catch errors early in the development process and improve code maintainability. Two important concepts in TypeScript’s type system are union and intersection types. These concepts allow developers to create more flexible and precise type definitions. Let’s discuss them in detail.

Union type

Union types in TypeScript allow a variable to have multiple types. This means that a variable declared with a union type can store values of any type. Union types are denoted using the pipe (|) symbol between type names. It is particularly useful when a function or variable can accept multiple values.

Using union type in variables

Let’s have an example of using unions with variables in the following playground:

let variable: string | number;
variable = "Hello";
console.log(variable); // Output: Hello
variable = 14;
console.log(variable); // Output: 14

In the code above:

  • Line 1: We declare a variable named variable with the type string | number. Here, string | number denotes a union type, meaning the variable can hold either string or number type values.

  • Lines 3–4: We assign the string "Hello" to the variable and log it to the console.

  • Lines 6–7: Similarly, we assign the number 14 to the variable and log it to the console.

Let’s see what happens if we assign some other value to the variable:

let variable: string | number;
variable = true; // error TS2322: Type 'boolean' is not assignable to type 'string | number'.
console.log(variable);

In the code above, we try to assign a boolean value to the variable on line 3, which is incompatible with the declared variable type. Therefore, we encountered this error: index.ts(3,1): error TS2322: Type 'boolean' is not assignable to type 'string | number'.

Using union in functions

Similarly, we can use unions with the function parameters. Let’s have an example of it in the following playground:

function print_(value: string | number) {
console.log(value);
}
print_("Hello"); // Output: Hello
print_(123); // Output: 123

In the code above:

  • Lines 1–3: We define the print_() function that takes a parameter value with the type string | number. Here, string | number denotes a union type, meaning that the parameter value can accept the values of either string or number type. In this function, we call the console.log() method to print the value to the console.

  • Line 5: We call the print_() function with the string argument "Hello". As "Hello" is of type string, and the print_() function’s parameter value accepts both string and number, TypeScript infers the type of value to be a string for this invocation.

  • Line 6: Similarly, we call the print_() function with the number argument 123. As 123 is of type number, and the print_() function’s parameter value accepts both string and number, TypeScript infers the type of value as a number for this invocation.

Let’s see what happens if we pass some other value to the print_() function:

function print_(value: string | number) {
console.log(value);
}
print_(true); // error TS2345: Argument of type 'boolean' is not assignable to parameter of type 'string | number'.

In the code above, we try to pass a boolean value to the print_() function on line 5, which is not compatible with the declared type of value parameter. Therefore, we encountered this error: index.ts(5,8): error TS2345: Argument of type 'boolean' is not assignable to parameter of type 'string | number'.

Applications

Unions are used in various real-life applications. Some use cases are as follows:

  • They allow different data types of a function parameter, such as “string,” “number,” etc., so that the same function can process different types of inputs.

  • Optional parameters can be implemented using unions representing values that might be present or absent (null or undefined).

  • They are used to represent different system statuses, such as “To Do,” “In Progress,” “Done,” etc.

  • They are also used to handle different types of responses to an API call, such as “Success,” “Error,” etc.

Intersection type

Intersection types allow developers to combine multiple types into one. An intersection type is denoted using the ampersand (&) symbol between type names. It is particularly useful when we combine properties or behaviors from multiple types, creating a new type encompassing all the combined features.

Let’s have an example of using intersection type in the following playground:

interface Car {
make: string;
color: string;
}
interface Electric {
batteryCapacity: number;
}
type ElectricCar = Car & Electric;
const myCar: ElectricCar = {
make: "Tesla",
color: "Black",
batteryCapacity: 75
};
console.log("myCar:", myCar); // Output: myCar: { make: 'Tesla', color: 'Black', batteryCapacity: 75 }

In the code above:

  • Lines 1–4: We declare an interfaceInterfaces in TypeScript are used to define the structure of objects. named Car. It has two properties: make and color, both of type string.

  • Lines 6–8: We declare another interface named Electric. It has one property: batteryCapacity, which is of type number.

  • Line 10: We create a new type named ElectricCar using an intersection type (&). It combines properties from the Car and Electric interfaces, meaning objects of type ElectricCar must have all properties defined in both interfaces.

  • Lines 12–16: We declare a variable named myCar of type ElectricCar. The object has properties of make, color, and batteryCapacity, each with corresponding values.

  • Line 18: Lastly, we log the value of myCar to the console. The output string includes the make, color, and batteryCapacity properties with their respective values.

Applications

Intersections are used in various real-life applications. Some use cases are as follows:

  • They are used to enforce consistent data structures to guarantee the properties of all intersected data structures.

  • They are used to combine the roles and rights. Different roles can be combined with their rights and privileges to ensure the application’s security.

Unions vs. intersection types

The union types provide flexibility by accepting values of multiple types. The intersection types combine properties from multiple types into a single type. In other words, union types represent “or” relationships, while intersection types represent “and” relationships. Let’s compare both in the table below:

Feature

Union Type

Intersection Type

Usage

Union allows a variable to hold values of multiple types.

Intersection combines properties from multiple types into one.

Relationships

It represents the “or” relationship between types.

It represents the “and” relationship between types.

Syntax

It is defined using the pipe (|) symbol.

It is defined using the ampersand (&) symbol.

Compatibility

The variable can hold any value that matches one of the specified types.

The variable must satisfy all the individual types’ requirements.

Versatility

It enhances the versatility of functions and variables.

It creates a new type by combining properties from existing types.

Conclusion

Union and intersection types are powerful features in TypeScript that enable developers to create more flexible and precise type definitions. Using union types, variables, and functions can accept values of multiple types, providing flexibility without sacrificing type safety. Intersection types allow for combining properties from multiple types into one, enabling objects to satisfy multiple contracts or have combined functionality. Understanding and effectively using union and intersection types can greatly enhance the development experience and code quality in TypeScript projects.


Free Resources

Copyright ©2025 Educative, Inc. All rights reserved