Language: EN

typescript-intersecciones

Using Intersections in TypeScript

Intersections in TypeScript allow us to combine multiple types into a single type. That is, they serve to create a type that adds the properties of two types.

Intersection Syntax

An intersection type (Intersection Type) is defined using the & operator. The resulting type contains all the properties of the combined types.

type IntersectionType = Type1 & Type2;

Where Type1 and Type2 can be any type of object, interface, primitive type, etc.

Let’s see it with an example,

type A = { a: number };
type B = { b: string };

type C = A & B;
// C is equivalent to { a: number; b: string }

In the previous example,

  • The type C is an intersection of types A and B
  • This means that C will have both the property a from type A and the property b from type B.

Combining Interfaces

One of the most common ways to use intersection types is by combining interfaces. This is especially useful when we want to create an object that has properties from multiple interfaces:

interface Identifiable {
    id: number; // Property id of type number
}

interface Nameable {
    name: string; // Property name of type string
}

// We define a type Person that is the intersection of Identifiable and Nameable
type Person = Identifiable & Nameable;

const person: Person = {
    id: 1,
    name: "Luis"
};

console.log(person.id); // Prints: 1
console.log(person.name); // Prints: Luis

In this example,

  • Person is an intersection type that combines the properties of Identifiable and Nameable
  • Therefore, person must have both an id and a name

Extending Types

Intersection types are useful for extending existing types (for example, if you want to add additional properties to an already defined type):

interface Base {
  id: number;
}

type WithName = Base & { name: string };

const item: WithName = {
  id: 1,
  name: "Item 1"
};

In this example, WithName extends the Base type by adding a name property.

Intersections with Generic Types

Intersections can be combined with generic types to create even more flexible and reusable types.

function combine<T, U>(obj1: T, obj2: U): T & U {
    return { ...obj1, ...obj2 };
}

const object1 = { name: "Luis" };
const object2 = { age: 30 };

const combinedObject = combine(object1, object2);

console.log(combinedObject.name); // Luis
console.log(combinedObject.age); // 30

In this example,

  • The function combine accepts two objects of generic types T and U
  • It returns an object that is the intersection of both types.

Notice that it is an elegant way to destructure two arbitrary objects and combine them, maintaining static typing

Considerations and Issues

Impossible Intersections

Care must be taken when defining intersections of combinations of primitive types, because we can give rise to impossible types that simply cannot be satisfied.

type Id = number;
type Name = string;

type User = Id & Name;

const userId: User = 12345; // Error: cannot be just a number
const userName: User = "Luis"; // Error: cannot be just a string

In this example, the type User is impossible because a variable cannot be both number and string at the same time.

Intersection with any Types

When intersecting a type with any, the result will be any. For example:

type A = { a: number };
type B = any;

type C = A & B; // C is of type any