TypeScript Union and Intersection Types

TypeScript provides powerful type system features that help you write safer and more predictable code. Among these features are union and intersection types, which offer flexibility in defining and managing complex types. This article introduces these concepts and provides examples to illustrate their usage.

What Are Union Types?

Union types allow a variable to hold values of different types. This is useful when you need to represent a value that could be one of several types. Union types are denoted using the | (pipe) symbol.

Defining Union Types

To define a union type, you specify multiple types separated by the | symbol:

let value: string | number;

value = "Hello, TypeScript"; // Valid
value = 42; // Valid
value = true; // Error: Type 'boolean' is not assignable to type 'string | number'

In this example, the variable value can be either a string or a number, but not a boolean.

Using Union Types in Functions

Union types are particularly useful in functions where parameters or return types can be multiple types:

function formatValue(value: string | number): string {
  if (typeof value === "string") {
    return value.toUpperCase();
  } else {
    return value.toFixed(2);
  }
}

console.log(formatValue("hello")); // Output: HELLO
console.log(formatValue(123.456)); // Output: 123.46

The formatValue function takes a parameter that can be either a string or a number and formats it accordingly.

What Are Intersection Types?

Intersection types allow you to combine multiple types into one. This means that a value of the intersection type will satisfy all the types in the intersection. Intersection types are denoted using the & (ampersand) symbol.

Defining Intersection Types

To define an intersection type, you specify multiple types separated by the & symbol:

interface Person {
  name: string;
}

interface Employee {
  employeeId: number;
}

type EmployeePerson = Person & Employee;

const john: EmployeePerson = {
  name: "John Doe",
  employeeId: 1234
};

console.log(john.name); // Output: John Doe
console.log(john.employeeId); // Output: 1234

In this example, the EmployeePerson type combines the Person and Employee interfaces, resulting in a type that has both name and employeeId properties.

Using Intersection Types in Functions

Intersection types can also be used in functions to require multiple type properties:

function printEmployeeDetails(employee: Person & Employee): void {
  console.log(`Name: ${employee.name}`);
  console.log(`Employee ID: ${employee.employeeId}`);
}

const jane: EmployeePerson = {
  name: "Jane Smith",
  employeeId: 5678
};

printEmployeeDetails(jane);
// Output:
// Name: Jane Smith
// Employee ID: 5678

The printEmployeeDetails function requires an argument that satisfies both the Person and Employee types.

Combining Union and Intersection Types

You can combine union and intersection types to create complex type definitions:

type Shape = Circle | Rectangle;

interface Circle {
  kind: "circle";
  radius: number;
}

interface Rectangle {
  kind: "rectangle";
  width: number;
  height: number;
}

function getArea(shape: Shape): number {
  if (shape.kind === "circle") {
    return Math.PI * shape.radius * shape.radius;
  } else {
    return shape.width * shape.height;
  }
}

const myCircle: Circle = { kind: "circle", radius: 10 };
const myRectangle: Rectangle = { kind: "rectangle", width: 20, height: 30 };

console.log(getArea(myCircle)); // Output: 314.159...
console.log(getArea(myRectangle)); // Output: 600

In this example, the Shape type is a union of Circle and Rectangle, and the getArea function handles both types accordingly.

Conclusion

Union and intersection types in TypeScript provide powerful ways to manage and combine types, offering flexibility and precision in type definitions. Union types allow a variable to be one of several types, while intersection types combine multiple types into one. By using these features, you can create more robust and type-safe applications.

Practice using union and intersection types to get comfortable with their capabilities and improve your TypeScript coding skills.