TypeScript: conditionally type a property based on another property

1 min readtypescript

Let’s say we want to model a workout plan in TypeScript.

A workout plan has:

Depending on the workout type, the list of exercises should be typed accordingly, i.e., a cardio exercise has distance and duration, while a strength training exercise has number of sets, number of reps, and weight.

How can we achieve that?

The following is one way to do it. First, we set a base type without type and list of exercises:

type WorkoutPlanBase = {
id: number
workoutName: string
created_at: Date
updated_at: Date
}

Then, we define our workout plan type using an intersection (to extend from the base type) and a discriminated union (where we use the literal type for workoutType to specify the respective two possible types for exercises):

type WorkoutPlan = WorkoutPlanBase &
(
| { workoutType: "strength", exercises: StrengthTrainingExercise[] }
| { workoutType: "cardio", exercises: CardioExercise[] }
);

This example from Blaine Garret’s article was very helpful for my understanding.