When we define types for our objects in TypeScript, we explicitly include object property types. It means you can add all the defined properties while creating your objects.
But sometimes we might want to add some properties conditionally based on another property value. Let's see an example to understand the situation.
type Vehicle = {
type: 'bus' | 'truck'
wheels: number
totalSeats?: number
totalCargo?: number
}
const bus: Vehicle = {
type: 'bus',
wheels: 6,
totalSeats: 50,
totalCargo: 200
}
In this Vehicle type, I have 4 properties. The type
property can be either a bus
or truck
and, totalSeats
and totalCargo
are optional properties.
I want to add totalSeats
property if the value of type
property is bus
. If the value of type
property is truck
, I will add totalCargo
property to my object.
But as you can see, even though I am creating a bus object, I can define both totalSeats
and totalCargo
properties in this object. TypeScript won't show any error.
How can you solve this problem?
In this blog post, I am going to show you how to define properties in objects depending on the value of another property.
Add Properties Conditionally Based on Another Property
To define properties conditionally, you have to combine multiple types. In the previous example, the Vehicle
type has one common property which is wheels
.
We need to create 2 separate types for bus
and truck
then add the wheel property to them.
type Bus = {
type: 'bus'
totalSeats: number
}
type Truck = {
type: 'truck'
totalCargo: number
}
type Vehicle = {
wheels: number
} & (Bus | Truck)
The Bus
type represents a bus and has two properties: type
, which is set to 'bus'
, and totalSeats
, which specifies the total number of seats on the bus.
The Truck
type represents a truck and has two properties: type
, which is set to 'truck'
, and totalCargo
, which indicates the total amount of cargo the truck can carry.
The Vehicle type is a combination of either a Bus
or a Truck
and an object that contains the wheels
property.
const bus: Vehicle = {
type: 'bus',
wheels: 6,
totalSeats: 50,
}
const truck: Vehicle = {
type: 'truck',
wheels: 6,
totalCargo: 200,
}
When we create bus
and truck
objects using the Vehicle
type, you can't define totalCargo
property if the value of type
property is bus
. TypeScript will show an error if you try it.
You also can't define totalSeats
property in a truck
type object. But the wheels
property is common for both objects.
Also Read: TypeScript Type vs. Interface: Which One Should You Use?
Access Dynamic Properties Using Type Guard
As we are adding properties conditionally, we have to use type guards to access those properties. You can access type
and wheels
properties because objects of type Vehicle
have these 2 properties.
But if you want to get the values of totalSeats
and totalCargo
properties, you have to check the value of type
property. Because these 2 properties depend on the type
property.
const truck: Vehicle = {
type: 'truck',
wheels: 6,
totalCargo: 200,
}
const vehicleInfo = (vehicle: Vehicle) => {
if (vehicle.type === 'bus') {
console.log(vehicle.totalSeats)
}
if (vehicle.type === 'truck') {
console.log(vehicle.totalCargo)
}
}
vehicleInfo(truck)
The vehicleInfor()
function takes a parameter of type Vehicle
. To get the value of totalSeats
property, I am checking if the type
property is equal to bus
.
Again I am checking if the type
is equal to truck
to access the totalCargo
property. If you don't check the type property before accessing these 2 properties, TypeScript will give an error.