Home > OS >  TS2345: Argument of type 'Observable<TodoInterface[]>' is not assignable to paramete
TS2345: Argument of type 'Observable<TodoInterface[]>' is not assignable to paramete

Time:08-04

I'm in the middle of experimenting with some stuff in a project and I run into the erorr message written in the title.

First off, I have a BehaviorSubject array into which I place all my items:

todos$ = new BehaviorSubject<TodoInterface[]>([]);    

addTodo(text: string): void {
    const newTodo: TodoInterface = {
      id: Math.random().toString(16),
      text: text,
      isCompleted: false,
    };
    const updateTodos = [...this.todos$.getValue(), newTodo];
    this.todos$.next(updateTodos);    
  }

This code was written by an instructor on Youtube but he used the getValue() method of BehaviorSubject which I read is a bad approach and should not be used regularly. Hence, to rework a little part I decided to change the code from this:

removeTodo(id: string): void { 
  const updatedTodos = this.todos$.getValue().filter((todo) => todo.id !== id);
  this.todos$.next(updatedTodos);
}

To this:

removeTodo(id: string): void {
  const updatedTodos = this.todos$.pipe(
    map((todos) => todos.filter((todo) => todo.id !== id))
  );    
  this.todos$.next(updatedTodos);
}

My assumption was simple: all I want is to put all the data into the pipe, filter out the items I need and then push the remaining items back into my original array. However, this didn't work, I received the mentioned error. Can anyone tell me what I did wrong here?

I thought the problem is that I didn't subscribe to this stream but I don't know where to subscribe to it if not here, directly after the end of the pipe which did not work out. Here is the component part (if important at all):

removeTodo(): void {
   this.todosService.removeTodo(this.todoProps.id);
}

CodePudding user response:

Why is getValue() a bad practice? That is exactly why behaviour subjects are a great observable to use for storing data in services. You retrieve the current value from the behaviour subject, use that value to generate a new object to replace it as the next item to come down the stream. This is the behaviour subject way.

You are trying to push an observable into your behaviour subject which is just completely wrong. Your observable takes an array for the next value, it doesn't take and observable as it's next value. The original approach of getting the current value and filtering out the item to remove is the correct way.

CodePudding user response:

As mentioned by @Adrian in the comments, the purpose of getValue is to get the current value without subscribing to the observable. And hence, it should be used.

Here is an alternate approach:

You need to subscribe to the observable to access the value. So, the code that you require will be:

removeTodo(id: string): void {
  let newTodos = null;
  this.todos$.pipe(take(1)).subscribe((todos) => {
     //PERFORM YOUR FILTERING HERE AND ASSIGN IT TO `newTodos`.
      newTodos = todos.filter((todo) => todo.id !== id)
   });
  this.todos$.next(newTodos);
}

Notice that I am using take(1) in Pipe. This will make sure that you just get a single value and the subscription is cleared up later.

The Instructor uses getValue as you just need the current value for performing the removal.

If the task was to show all these Todos then, you will keep the subscription active.

  • Related