Breaking: Subscription.add() no longer returns a Subscription. It now returns void.
Copy
Ask AI
import { Subscription, interval } from 'rxjs';const subscription = new Subscription();const sub1 = subscription.add( interval(1000).subscribe());// sub1 is a Subscriptionsubscription.remove(sub1);
import { AsyncSubject } from 'rxjs';const subject = new AsyncSubject();// subject._subscribe() // TypeScript error in v7
BehaviorSubject
_subscribe method is now protected (was public)
value is now a getter instead of readonly property
Cannot be forcibly set
Copy
Ask AI
import { BehaviorSubject } from 'rxjs';const subject = new BehaviorSubject(0);console.log(subject.value); // Still works// (subject as any).value = 1; // Won't work like it might have in edge cases
ReplaySubject
_subscribe method is now protected (was public)
_getNow method removed
No longer schedules emissions when a scheduler is provided
Copy
Ask AI
import { ReplaySubject, asapScheduler } from 'rxjs';const subject = new ReplaySubject(2, 3000, asapScheduler);// Emissions are scheduled
defer no longer allows factories to return void or undefined. Must return a valid ObservableInput.
Copy
Ask AI
import { defer } from 'rxjs';const source$ = defer(() => { console.log('side effect'); // Returns undefined - breaks in v7!});
fromEvent
Signatures changed - separate overloads for each target type. Passing options to incompatible targets now causes TypeScript errors.
Copy
Ask AI
import { fromEvent } from 'rxjs';const clicks$ = fromEvent(document, 'click', { once: true // Type-checked against DOM EventTarget});
iif
iif no longer allows undefined as result arguments.
Copy
Ask AI
import { iif } from 'rxjs';const result$ = iif( () => Math.random() > 0.5, undefined, // Breaks in v7! of('false'));
isObservable
No longer has a generic parameter. Returns Observable<unknown> - you must cast the result.
Copy
Ask AI
import { isObservable, of } from 'rxjs';const value = of(1);if (isObservable<number>(value)) { // value is Observable<number>}
pairs
pairs requires Object.entries polyfill for IE. Consider using from(Object.entries(obj)) instead.
Copy
Ask AI
import { from } from 'rxjs';const obj = { a: 1, b: 2, c: 3 };from(Object.entries(obj)).subscribe(console.log);
race
race no longer subscribes to subsequent observables if a source synchronously errors or completes.
Copy
Ask AI
import { race, of, throwError } from 'rxjs';import { tap } from 'rxjs/operators';race( throwError(() => new Error('immediate')), of(1).pipe(tap(() => console.log('This side effect won\'t run')))).subscribe();
The following operators now require their duration selectors to emit a next notification, not just complete:
audit - duration must emit next
debounce - duration must emit next
throttle - duration must emit next
bufferToggle - closing selector must emit next
bufferWhen - closing selector must emit next
windowToggle - closing selector must emit next
delayWhen - duration must emit value, not just complete
sample - notifier must emit next, not just complete
Copy
Ask AI
import { interval, audit, EMPTY } from 'rxjs';interval(100).pipe( audit(() => EMPTY) // EMPTY just completes - won't trigger audit!).subscribe();
buffer
Multiple behavioral changes:
Now subscribes to source before closing notifier (order reversed)
Final buffered values always emitted
Closing notifier completion no longer completes result
Copy
Ask AI
import { interval, buffer } from 'rxjs';import { take } from 'rxjs/operators';const notifier$ = interval(1000).pipe(take(3));interval(100).pipe(buffer(notifier$)).subscribe();// Completes when notifier completes
count
Predicate no longer receives source observable as third argument.
Copy
Ask AI
import { of } from 'rxjs';import { count } from 'rxjs/operators';of(1, 2, 3).pipe( count((value, index, source) => { console.log(source); // Had access to source return value > 1; }));
defaultIfEmpty
defaultIfEmpty requires a value argument. No longer converts undefined to null.
Copy
Ask AI
import { EMPTY } from 'rxjs';import { defaultIfEmpty } from 'rxjs/operators';EMPTY.pipe( defaultIfEmpty() // Error in v7!);
finalize
Finalize callbacks now run in pipeline order (not reversed).
Copy
Ask AI
import { of } from 'rxjs';import { finalize } from 'rxjs/operators';of(1).pipe( finalize(() => console.log('1')), finalize(() => console.log('2'))).subscribe();// Logs: "2" then "1" (reversed)
map
thisArg now defaults to undefined instead of MapSubscriber.
Copy
Ask AI
import { of } from 'rxjs';import { map } from 'rxjs/operators';// Only affects function (not arrow function) with 'this' referenceof(1, 2, 3).pipe( map(function(value) { console.log(this); // undefined in v7, was MapSubscriber in v6 return value * 2; }));
mergeScan
mergeScan no longer emits inner state again upon completion.
Copy
Ask AI
import { of } from 'rxjs';import { mergeScan } from 'rxjs/operators';of(1, 2, 3).pipe( mergeScan((acc, value) => of(acc + value), 0)).subscribe(console.log);// v6: 1, 3, 6, 6 (duplicated final value)// v7: 1, 3, 6 (no duplicate)
single
single now throws more specific errors. Check error handling logic.
Copy
Ask AI
import { of, empty } from 'rxjs';import { single } from 'rxjs/operators';// Throws EmptyError if no valuesempty().pipe(single()).subscribe();// Throws SequenceError if multiple valuesof(1, 2, 3).pipe(single()).subscribe();// Throws NotFoundError if predicate never matchesof(1, 2, 3).pipe( single(x => x > 10)).subscribe();
skipLast
skipLast no longer errors with negative numbers - returns source instead.
Copy
Ask AI
import { of } from 'rxjs';import { skipLast } from 'rxjs/operators';// v6: throws error// v7: returns source unchangedof(1, 2, 3).pipe( skipLast(-1)).subscribe(console.log); // 1, 2, 3
take
take now throws runtime errors for negative or NaN arguments.
Copy
Ask AI
import { of } from 'rxjs';import { take } from 'rxjs/operators';of(1, 2, 3).pipe( take(-1) // Throws TypeError in v7).subscribe();of(1, 2, 3).pipe( take(NaN) // Throws TypeError in v7 ).subscribe();
takeLast
takeLast throws TypeError for invalid arguments (no args or NaN).
Copy
Ask AI
import { of } from 'rxjs';import { takeLast } from 'rxjs/operators';of(1, 2, 3).pipe( takeLast() // Throws TypeError).subscribe();
window
windowBoundaries no longer completes the result.
Copy
Ask AI
import { interval } from 'rxjs';import { window, endWith, skipLast, take } from 'rxjs/operators';const notifier$ = interval(1000).pipe(take(3));interval(100).pipe( window(notifier$.pipe(endWith(true))), skipLast(1)).subscribe();
zip
Multiple changes to zip behavior:
Zipping single array has different result
Iterables no longer consumed “as needed” (can lock up with infinite iterables)
Copy
Ask AI
import { zip, of } from 'rxjs';function* infiniteGenerator() { let i = 0; while (true) yield i++;}// v7: Locks up trying to read entire iterable!zip(of(1, 2, 3), infiniteGenerator()).subscribe();