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
Cis an intersection of typesAandB - This means that
Cwill have both the propertyafrom typeAand the propertybfrom typeB.
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,
Personis an intersection type that combines the properties ofIdentifiableandNameable- Therefore,
personmust have both anidand aname
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
combineaccepts two objects of generic typesTandU - 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