Intersections in TypeScript allow us to combine multiple types into a single type. That is, they are used to create a type that adds the properties of two types.
Intersection Syntax
An 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 object type, 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 typesA
andB
- This means that
C
will have both the propertya
from typeA
and the propertyb
from typeB
.
Combining Interfaces
One of the most common ways to use intersection types is 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 ofIdentifiable
andNameable
- Therefore,
person
must have both anid
and 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 type Base
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
combine
function accepts two objects of generic typesT
andU
- Returns an object that is the intersection of both types.
Note that this is an elegant way to destructure two arbitrary objects and combine them, while maintaining static typing
Considerations and Issues
Impossible Intersections
Care must be taken when defining intersections of combinations of primitive types, because we can end up with 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