TypeScript: conditionally type a property based on another property
Let’s say we want to model a workout plan in TypeScript.
A workout plan has:
- id, name, creation date, updated date
- type (cardio or strength training)
- a list of exercises
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.