A the document describes the tap() with following code:
import { fromEvent } from 'rxjs';
import { tap, map } from 'rxjs/operators';
const clicks = fromEvent(document, 'click');
const positions = clicks.pipe(
tap(ev => console.log(ev)),
map(ev => ev.clientX),
);
positions.subscribe(x => console.log(x));
but I do not understand why to use tap. Is it just logging. The explanation says
Map every click to the clientX position of that click, while also logging the click event
Perform a side effect for every emission on the source Observable, but return an Observable that is identical to the source
Example:
tap(value => console.log(value))
Applies a given project function to each value emitted by the source Observable, and emits the resulting values as an Observable.
Example:
map(value => 'prefix' + value)
Why not to use map or other operators for side effects like log
You can use map, scan and any other operator that gets a function and returns an individual result to implement side effects. This will make your code very hard to understand/debug/find bugs in the future. Provided that, in general it is not good to use side effects in pipes. Logging can be an exception if you need/want it and don't want to have lot's of subscriptions for every logging point. Therefore tap can be useful. You could adapt this to the following steps:
Example for how you could but should not
switchMap(value => {
console.log(value); // Side effect 1
const newValue = foo(value);
console.log(newValue); // Side effect 2
return of(newValue);
})
Example of how you could do and should
tap(console.log), // Side effect 1
switchMap(value => of(foo(value))),
tap(console.log) // Side effect 2
Last word: When you write initially code that brings not much of an benefit. The larget your project gets and the moment other people try to find bugs it will improve saved time a lot.