Intersection Types in TypeScript

Intersection Types in TypeScript

This article explains intersection types in TypeScript.

YouTube Video

Intersection Types in TypeScript

In TypeScript, intersection types are a way to combine multiple types to create a new type.

What are Intersection Types?

Intersection types allow you to combine multiple types to define a new type with all properties of those types. Intersection types are defined using the & symbol and require all properties from each constituent type.

Example:

1type A = { name: string };
2type B = { age: number };
3
4type C = A & B;
5
6const person: C = {
7    name: "John Doe",
8    age: 30
9};

In this code, by defining type C = A & B, the C type becomes an object type that has both name and age.

Benefits of Intersection Types

By using intersection types, you can reuse existing types and define more flexible and composite types. This enhances the maintainability and extensibility of your code. Additionally, intersection types can apply constraints of multiple different types simultaneously, thereby enhancing type safety.

Benefits:

  • Reusability: By combining multiple types, you can reduce redundant definitions and reuse existing types.
  • Type Safety: Intersection types enhance type checking by allowing only objects that satisfy conditions of multiple types.

Use Cases for Intersection Types

Intersection types are extremely useful when extending objects or interfaces. In particular, it is useful when you want to represent objects with multiple properties.

Use Case 1: Objects with Multiple Interfaces

 1interface Drivable {
 2    drive(): void;
 3}
 4
 5interface Flyable {
 6    fly(): void;
 7}
 8
 9type Vehicle = Drivable & Flyable;
10
11const car: Vehicle = {
12    drive() {
13        console.log("Driving on the road");
14    },
15    fly() {
16        console.log("Flying in the sky");
17    }
18};
19
20car.drive(); // "Driving on the road"
21car.fly();   // "Flying in the sky"

In this example, the Vehicle type is defined as an intersection type combining Drivable and Flyable. An object of type Vehicle must implement both the drive() and fly() methods.

Use Case 2: Combining Classes and Intersection Types

By combining classes and intersection types, it is possible to create objects that have the properties of multiple interfaces.

 1interface Person {
 2    name: string;
 3}
 4
 5interface Employee {
 6    employeeId: number;
 7}
 8
 9type PersonEmployee = Person & Employee;
10
11class CompanyWorker implements PersonEmployee {
12    constructor(public name: string, public employeeId: number) {}
13
14    getDetails() {
15        return `${this.name}, Employee ID: ${this.employeeId}`;
16    }
17}
18
19const worker = new CompanyWorker("Alice", 123);
20console.log(worker.getDetails()); // "Alice, Employee ID: 123"

Here, we use the intersection type PersonEmployee of Person and Employee to make the CompanyWorker class have the properties of both.

Points to Consider with Intersection Types

An important point when using intersection types is to be aware of the possibility of property conflicts. If properties with the same name have different type annotations across different types, an error may occur.

Example of Caution:

1type A = { id: number };
2type B = { id: string };
3
4type C = A & B;
5
6// Error: Type 'number' and 'string' are not compatible
7const obj: C = {
8    id: 1
9};

In this example, the id properties of A and B conflict, causing an error when defining an object with type C. In such cases, a design review is necessary to avoid property conflicts.

Code Example with Type Annotations for Intersection Types

Finally, here is a real code example that includes type annotations.

Example 1: Displaying Object Details

 1type ContactInfo = { phone: string; email: string };
 2type Address = { city: string; postalCode: string };
 3
 4type PersonDetails = ContactInfo & Address;
 5
 6const details: PersonDetails = {
 7    phone: "123-4567",
 8    email: "example@mail.com",
 9    city: "New York",
10    postalCode: "10001"
11};
12
13console.log(details);
  • This code combines the ContactInfo and Address interfaces to create a new type called PersonDetails.

Example 2: Object with Additional Properties

 1interface BasicInfo {
 2    name: string;
 3    age: number;
 4}
 5
 6interface WorkInfo {
 7    company: string;
 8    position: string;
 9}
10
11type FullInfo = BasicInfo & WorkInfo;
12
13const employee: FullInfo = {
14    name: "Bob",
15    age: 28,
16    company: "Tech Corp",
17    position: "Engineer"
18};
19
20console.log(`${employee.name} is a ${employee.position} at ${employee.company}`);
  • This code combines the BasicInfo and WorkInfo interfaces to create a new type called FullInfo.

Conclusion

TypeScript's intersection types are a powerful feature for combining multiple types into a new type. This enhances code reusability and safety, enabling complex type definitions. By effectively leveraging design flexibility while being cautious of type conflicts, you can achieve robust and highly readable code.

You can follow along with the above article using Visual Studio Code on our YouTube channel. Please also check out the YouTube channel.

YouTube Video