Understanding the design principles and semantic guidelines that govern RxJS operators
Starting in RxJS v8, all operators in the core library MUST meet specific semantic guidelines. In v7, operators SHOULD meet these guidelines. This document defines the predictable behavior users can expect from RxJS.
These semantics ensure consistent behavior across all RxJS operators and provide a predictable experience for library users.
An operator is referentially transparent if you can capture its return value and use it on multiple Observables without any shared state.
Copy
Ask AI
import { map } from 'rxjs';// Capture the operator onceconst double = map(x => x * 2);// Use on multiple observables without side effectsa$.pipe(double).subscribe();b$.pipe(double).subscribe();c$.pipe(double).subscribe();// Each usage is independent
Notifiers MUST accept any type convertible to Observable with from:
Copy
Ask AI
import { takeUntil, from } from 'rxjs';// Accept Observablesource$.pipe(takeUntil(other$))// Accept Promisesource$.pipe(takeUntil(Promise.resolve()))// Accept Arraysource$.pipe(takeUntil([1, 2, 3]))
2
Only Next Values as Notifications
Only next emissions from notifiers count as notifications:
Copy
Ask AI
import { takeUntil, EMPTY, throwError } from 'rxjs';// This WILL trigger takeUntilsource$.pipe(takeUntil(of(1)))// This will NOT trigger takeUntil (completes without emitting)source$.pipe(takeUntil(EMPTY))// This will NOT trigger takeUntil (errors without emitting)source$.pipe(takeUntil(throwError(() => new Error('fail'))))
3
Subscribe to Direct Notifiers First
Notifiers provided directly MUST be subscribed to BEFORE the source:
Copy
Ask AI
import { takeUntil } from 'rxjs';// notifier$ is subscribed BEFORE source$source$.pipe(takeUntil(notifier$))// Order: notifier$ subscription → source$ subscription
4
Subscribe to Factory Notifiers ASAP
Notifiers from factory functions SHOULD be subscribed at earliest moment:
Copy
Ask AI
import { retryWhen, delay } from 'rxjs';source$.pipe( retryWhen(errors$ => // This factory is called when needed // Subscription happens as soon as error occurs errors$.pipe(delay(1000)) ))
Creation function names MUST NOT end in With. That suffix is reserved for operators.
Copy
Ask AI
// Good - Creation functionsof(1, 2, 3)from([1, 2, 3])interval(1000)merge(a$, b$, c$)// Good - Related operatorsconcatWith(b$)mergeWith(c$)startWith(0)
Creation functions MAY have result selectors (unlike operators):
Copy
Ask AI
import { combineLatest } from 'rxjs';// Allowed for creation functionscombineLatest( [source1$, source2$], (a, b) => a + b // Result selector OK here).subscribe(console.log);