I am working on an Angular project following a Udemy course (so the code it should be correct) but I am finding the following problem.
The original code in the course is:
export class TrainingService {
exerciseChanged: Subject<Exercise> = new Subject<Exercise>();
private availableExercise: Exercise[] = [
{ id: 'crunches', name: 'Crunches', duration: 30, calories: 8 },
{ id: 'touch-toes', name: 'Touch Toes', duration: 180, calories: 15 },
{ id: 'side-lunges', name: 'Side Lunges', duration: 120, calories: 18 },
{ id: 'burpees', name: 'Burpees', duration: 60, calories: 8 }
];
private runningExercise: Exercise;
getAvailableExercises(): Exercise[] {
return this.availableExercise.slice();
}
startExercise(selectedId: string) {
this.runningExercise = this.availableExercise.find(ex => ex.id === selectedId);
this.exerciseChanged.next({ ...this.runningExercise});
}
}
So as you can see the course instructor defined this variable:
private runningExercise: Exercise;
The problem is that doing in this way I obtain the following error on the first line of my startExercise() method:
this.runningExercise = this.availableExercise.find(ex => ex.id === selectedId);
the error is:
Type 'Exercise | undefined' is not assignable to type 'Exercise'.
Type 'undefined' is not assignable to type 'Exercise'.ts(2322)
Basically it seems that for the compiler the result of the find() method can be undefined so it can't do the assignment.
So I fixed in this way:
private runningExercise: Exercise | undefined;
So now the runningExercise variable can take an Exercise object but also an undefined value (maybe not so elegant). And now I have another problem when I try to execute the next() method on my Subject:
this.exerciseChanged.next({ ...this.runningExercise});
the problem is that it can't be an undefined value:
Error: src/app/training/training.service.ts:24:35 - error TS2345: Argument of type '{ id?: string | undefined; name?: string | undefined; duration?: number | undefined; calories?: number | undefined; date?: Date | undefined; state?: "completed" | "cancelled" | null | undefined; }' is not assignable to parameter of type 'Exercise'.
Types of property 'id' are incompatible.
Type 'string | undefined' is not assignable to type 'string'.
Type 'undefined' is not assignable to type 'string'.
24 this.exerciseChanged.next({ ...this.runningExercise});
~~~~~~~~~~~~~~~~~~~~~~~~~~
Why the Udemy code works in the instructor example but it is giving me this error on my PC? Maybe something related Angular version or some sort of code validation?
What is wrong? What am I missing? How can I try to fix it?
Thank you
CodePudding user response:
It's probably works for the Udemy instructor because they are either using an older version of Angular that does not have strict mode enable or they just simply disable it. To fix this problem you can perform a little bit of undefined
checking before before emitting the value:
startExercise(selectedId: string) {
this.runningExercise = this.availableExercise.find(ex => ex.id === selectedId);
if (!runningExcercise) return;
this.exerciseChanged.next({...this.runningExercise});
}
But yeah you should carefully consider what you want to do when selectedId
doesn't match any of your exercises, some options that I could think of is:
- Simple ignore it and end the function without emitting
exceriseChanged
(which is the code example above) - Throw an error because this shouldn't happen
- Emit an
undefined
value forexceriseChanged
- Emit an
Error
forexceriseChanged
CodePudding user response:
The find
can potentially return undefined
. You can type cast it
this.runningExercise = this.availableExercise.find(
ex => ex.id === selectedId
) as Exercise;
Note: I'd add an if
check too as suggested in @Nam's
answer