This one never gets old 🙂 — at least not as long as we’re working with Observables.
When working with Observables, we often don’t need every single value that comes through. That’s a perfect job for the filter
operator.
Fisherman’s net

Imagine you’re observing a stream of fish (Observable<number>
), where each fish has a size (1, 2, 3…). You’re only interested in fish size ≥ 3.
❌ Option 1: if
inside subscribe
The Hardworking Fisherman
observable$.subscribe(fishSize => {
if (fishSize >= 3) {
handleFish(fishSize); // Do the work
}
});
In this case, every fish that comes in is manually inspected. If it’s big enough, it’s processed; if not, it’s tossed aside.
You’re doing the filtering manually — every single time — even duplicating logic if you have multiple subscribers. This works, but it’s tedious and error-prone.
✅ Option 2: filter
inside pipe
The Smarter Fisherman with a Better Net
observable$
.pipe(filter(fishSize => fishSize >= 3))
.subscribe(handleFish);
Here, your net (the filter
) only lets through the fish you care about. Less code, cleaner logic, and better reuse — if the observable is shared, it’s already filtered for others, too.
Even better, you can keep composing it further:
observable$
.pipe(
filter(fishSize => fishSize >= 3),
map(fishSize => ({ size: fishSize, name: `Fish #${fishSize}` })),
take(5)
);
And when using the async
pipe in templates, no need to manually subscribe or unsubscribe:
<div *ngIf="bigFish$ | async as fish">
{{ fish.name }}
</div>
💬 Summary
Why catch and inspect every fish when you can use a smart net that only lets in the ones you want?
Use filter
in your pipe — not if
in your subscribe
.