Home     /Articles     /

Advanced TypeScript: Exploring Intersection and Union Types

Typescript

Advanced TypeScript: Exploring Intersection and Union Types

Written by Briann     |

December 05, 2024     |

1.4k |

Intersection and union types in TypeScript are advanced features that allow developers to create flexible, expressive, and reusable type definitions. These types are invaluable for building robust applications that handle a wide variety of use cases while maintaining type safety.

In this post, we’ll dive deep into intersection and union types, their differences, and practical examples to illustrate how to use them effectively.





1. What Are Union Types?

Union types enable a variable to hold one of multiple types. It’s like saying, "This can be type A or type B."


Example:

type StringOrNumber = string | number;

function format(value: StringOrNumber): string {
  return `Value is: ${value}`;
}

console.log(format("Hello")); // Output: Value is: Hello
console.log(format(42));      // Output: Value is: 42

Union types are useful for scenarios where a value might come in different forms, such as user input or API responses.





2. What Are Intersection Types?

Intersection types combine multiple types into one, requiring an object to satisfy all the included types. It’s like saying, "This must be type A and type B."


Example:

type User = {
  id: number;
  name: string;
};

type Admin = {
  role: "admin";
};

type AdminUser = User & Admin;

const admin: AdminUser = {
  id: 1,  name: "Alice",
  role: "admin",
};

console.log(admin);

Intersection types are perfect for merging multiple interfaces or types into a single comprehensive structure.





3. Combining Union and Intersection Types

You can use union and intersection types together to model complex scenarios.


Example:

type Animal = {
  species: string;
};

type Bird = {
  canFly: boolean;
};

type Dog = {
  isGoodBoy: boolean;
};

type Pet = (Bird & Animal) | (Dog & Animal);

const parrot: Pet = {
  species: "Parrot",
  canFly: true,
};

const labrador: Pet = {
  species: "Labrador",
  isGoodBoy: true,
};

console.log(parrot, labrador);

This approach is great for handling heterogeneous data with some shared properties.





4. Practical Use Cases

a. API Responses

Union types help handle multiple response shapes:

type SuccessResponse = {
  status: "success";
  data: string;
};

type ErrorResponse = {
  status: "error";
  message: string;
};

type ApiResponse = SuccessResponse | ErrorResponse;

function handleResponse(response: ApiResponse) {
  if (response.status === "success") {
    console.log(response.data);
  } else {
    console.error(response.message);
  }
}


b. Role-Based Access Control

Intersection types can represent users with overlapping roles:

type Viewer = {
  canView: boolean;
};

type Editor = {
  canEdit: boolean;
};

type EditorViewer = Viewer & Editor;

const user: EditorViewer = {
  canView: true,
  canEdit: true,
};

console.log(user);





5. Pitfalls to Avoid

While union and intersection types are powerful, misuse can lead to overly complex or ambiguous type definitions. Always strive for clarity and simplicity in your type design.





Conclusion


Intersection and union types are essential tools for crafting flexible and type-safe code in TypeScript. By mastering these concepts, you can tackle complex data structures and create reusable, maintainable codebases.

Powered by Froala Editor

Related Articles