Photo by Kevin Olson on Unsplash
Combining Types and Interfaces with & or | in TypeScript
Utilizing & or | for Combining Types in TypeScript
Table of contents
Today, I reviewed a piece of code where a variable could be of two types, but to enhance readability, the simple method is to use union and intersection.
In this example, we have defined two interfaces, Player
and Basket
, each representing a specific type.
interface Player {
id: number,
name: string
}
interface Basket {
points: number,
position: string
}
In the code, they were using both types in the declaration:
const player: Player & Basket = {
id: 1,
name: "lebron",
points: 12,
position: "foward"
}
We can simplify the code using union and intersection, but what are the differences between both?
Union Types
Union types, uses the |
operator, allows a variable to have multiple types. This means that a variable declared with a union type can hold values that belong to any of those types.
export type WNbaPlayer = Player | Basket
The WNbaPlayer
type is a union of both interfaces. This allows us to create an object that can accept either a Player
or a Basket
object.
They are handy for scenarios where flexibility is required, such as handling different input data formats or user inputs.
Example:
const player3 : WNbaPlayer = {
points: 3,
position: "foward"
}
//valid object
const player4 : WNbaPlayer = {
id: 3,
name: "Irina"
}
//valid
const player5 : WNbaPlayer = {
id: 1,
name: "Irina",
points: 33,
position: "center"
}
//valid
Next, let's proceed to intersection types.
Intersection Types
In contrast to union types, intersection types are denoted by the &
operator and require a variable to have properties from all specified types.
export type NbaPlayer = Player & Basket
They are valuable when you need to create composite types by combining properties from multiple sources and for situations like creating rich data structures or merging objects with specific properties.
Example:
const player2 : NbaPlayer = {
id: 1,
name: "Irina",
}
//invalid
const player3 : NbaPlayer = {
points: 33,
position: "center"
}
//invalid
const player2 : NbaPlayer = {
id: 1,
name: "Irina",
points: 33,
position: "center"
}
//!! Yeah is valid!
We create a NbaPlayer
type that combines properties from both interfaces using an intersection type. As a result, the player3
object must have properties from both Player
and Basket
.
Extends Interfaces
Thanks to Jörgen de Groot , we have another alternative by using extended interfaces, it add extra properties to the interfaces.
interface PlayerExtend extends Player {
//.... new properties
}
The extended interface is good when the new properties are used only by the extended interface, for example:
- If
Basket
interface cannot be used without thePlayer
interface then extension make sense, and we don't need to create a useless type.
- If
Basket
interface is used in other cases then use Intersection Types
interface PlayerExtended extends Player {
position: string,
points: string
}
Read more about extending types
Recap
To sum it up, it's super important to know when to use Union or Intersection Types if you want to write neat and easy-to-read code. Keep this in mind for your next challenge, and don't hesitate to check out the official Typescript documentation for a more in-depth look at the topic.
Feel free to play with the example code:
Have fun!