Oct 18 2024
Imagine we have a Vehicle
type in our app that we can represent like this:
type Vehicle = Car | Motorcycle | Bike;
type Car = {
brand: string;
model: string;
engine: string;
nrOfDoors: number;
hasClimateControl: boolean;
};
type Motorcycle = {
brand: string;
model: string;
engine: string;
};
type Bike = {
brand: string;
model: string;
type: string;
nrOfWheels: number;
};
Now we want to create a vehicle and log nrOfDoors
if it is a car. How would we do that?
const vehicle = createRandomVehicle();
// ❌ This won't work
console.log(vehicle.nrOfDoors);
if ("brand" in vehicle) {
// ❌ This won't work
console.log(vehicle.nrOfDoors);
}
// This will work
if ("nrOfDoors" in vehicle) {
console.log(vehicle.nrOfDoors);
}
// This will work too
if ("hasClimateControl" in vehicle) {
console.log(vehicle.nrOfDoors);
}
First, we need to check if the vehicle has a nrOfDoors
or hasClimateControl
property. Then TypeScript will know that the vehicle is a Car
, and we can access the nrOfDoors
property.
The process when TypeScript “gets to know” that the vehicle is a Car
is called a discriminated union. It is a pattern that allows TypeScript to narrow down the type of an object based on a specific property.
In simple terms, no other type has the nrOfDoors
property, so if we check for it, TypeScript will know that the object is a Car
.
But we won’t always know which property to check. In that case, we can use a common property that all types have. In this case, we will use the type
property.
type Vehicle = Car | Motorcycle | Bike;
type Car = {
type: "car";
brand: string;
model: string;
engine: string;
nrOfDoors: number;
hasClimateControl: boolean;
};
type Motorcycle = {
type: "motorcycle";
brand: string;
model: string;
engine: string;
};
type Bike = {
type: "bike";
brand: string;
model: string;
type: string;
nrOfWheels: number;
};
We need to make sure that the type
property is unique for each type so TypeScript can distinguish between them.
Now we can check for the type
property to know which type the vehicle is.
if (vehicle.type === "car") {
console.log(vehicle.nrOfDoors);
}
Also, it helps in various other cases like creating a new Vehicle
object manually.
const newVehicle: Vehicle = {
type: "car",
// From this point TypeScript knows that the object is a Car and will suggest only Car properties
};
That’s it. I hope you enjoyed this article.
Here’s an add-on for you: A brief summary of the article. You can use it to create flashcards (e.g., in Anki).
It is a pattern that allows TypeScript to narrow down the type of an object based on a specific property.
Example usage:
type Vehicle = Car | Motorcycle | Bike;
type Car = {
type: "car";
brand: string;
model: string;
engine: string;
nrOfDoors: number;
hasClimateControl: boolean;
};
type Motorcycle = {
type: "motorcycle";
brand: string;
model: string;
engine: string;
};
type Bike = {
type: "bike";
brand: string;
model: string;
type: string;
nrOfWheels: number;
};
if (vehicle.type === "car") {
console.log(vehicle.nrOfDoors);
}