Skip to main content

Deprecated APIs in RxJS v7

This page documents all APIs that are deprecated in RxJS v7. These APIs still work but will be removed in RxJS v8. Migrate to the recommended alternatives as soon as possible.

Promise Conversion

toPromise()

Deprecated in v7, will be removed in v8. Use firstValueFrom() or lastValueFrom() instead.
The toPromise() method has been deprecated because:
  1. The name doesn’t indicate which value (first or last) will be used
  2. The return type Promise<T | undefined> can be confusing
  3. The behavior with empty observables is inconsistent

Migration to lastValueFrom

Use lastValueFrom() when you want the final emitted value:
import { interval } from 'rxjs';
import { take } from 'rxjs/operators';

async function example() {
  const source$ = interval(1000).pipe(take(5));
  const result = await source$.toPromise();
  console.log(result); // 4 (last value)
}

Migration to firstValueFrom

Use firstValueFrom() when you want the first emitted value:
import { interval } from 'rxjs';
import { map } from 'rxjs/operators';

async function example() {
  // With toPromise, you'd need take(1)
  const source$ = interval(1000).pipe(
    map(x => x * 2),
    take(1)
  );
  const result = await source$.toPromise();
  console.log(result); // 0
}

Handling Empty Observables

import { EMPTY } from 'rxjs';

async function example() {
  const result = await EMPTY.toPromise();
  console.log(result); // undefined
}
Warning: Only use these functions with observables that will complete. For potentially infinite observables, add timeout, take, takeWhile, or takeUntil to prevent memory leaks.

Subscribe Arguments

Multiple Function Arguments

Deprecated in v6.4, will be removed in v8. Use observer objects instead of multiple function arguments.
Passing multiple function arguments to subscribe() is deprecated. This affects both subscribe() and the tap operator.

Why This Was Deprecated

  1. Readability: subscribe(doSomething, doSomethingElse, lol) is unclear
  2. Future flexibility: Second argument may be used for configuration (AbortSignal, etc.)
  3. Null confusion: subscribe(null, null, onComplete) is hard to read

Migration Examples

import { of } from 'rxjs';

of(1, 2, 3).subscribe(
  value => console.log(value),
  err => console.error(err),
  () => console.log('complete')
);
import { throwError } from 'rxjs';

throwError(() => new Error('oops')).subscribe(
  null,
  err => console.error(err)
);
import { EMPTY } from 'rxjs';

EMPTY.subscribe(
  null,
  null,
  () => console.log('complete')
);
Single next callback is still fine: of(1, 2, 3).subscribe(v => console.log(v)) is the recommended pattern when you only need the next callback.

tap Operator

The same deprecation applies to tap:
import { of } from 'rxjs';
import { tap } from 'rxjs/operators';

of(1, 2, 3).pipe(
  tap(
    v => console.log('next:', v),
    err => console.error('error:', err),
    () => console.log('complete')
  )
).subscribe();

Multicasting APIs

Deprecated in v7, will be removed in v8. Multicasting APIs have been simplified to connectable, connect, and share.

ConnectableObservable

import { ConnectableObservable, timer, Subject } from 'rxjs';

const tick$ = new ConnectableObservable(
  timer(1000),
  () => new Subject()
);
tick$.connect();

multicast

import { timer, multicast, Subject, ConnectableObservable } from 'rxjs';

const tick$ = timer(1000).pipe(
  multicast(() => new Subject())
) as ConnectableObservable<number>;
tick$.connect();
import { timer, multicast, Subject, ConnectableObservable } from 'rxjs';

const tick$ = timer(1000).pipe(
  multicast(new Subject())
) as ConnectableObservable<number>;
tick$.connect();
import { timer, multicast, Subject, refCount } from 'rxjs';

const tick$ = timer(1000).pipe(
  multicast(() => new Subject()),
  refCount()
);
import { timer, multicast, Subject, combineLatest } from 'rxjs';

const tick$ = timer(1000).pipe(
  multicast(
    () => new Subject(),
    source => combineLatest([source, source])
  )
);

publish Variants

import { timer, publish, ConnectableObservable } from 'rxjs';

const tick$ = timer(1000).pipe(
  publish()
) as ConnectableObservable<number>;
tick$.connect();
import { timer, publishBehavior, ConnectableObservable } from 'rxjs';

const tick$ = timer(1000).pipe(
  publishBehavior(0)
) as ConnectableObservable<number>;
tick$.connect();
import { timer, publishLast, ConnectableObservable } from 'rxjs';

const tick$ = timer(1000).pipe(
  publishLast()
) as ConnectableObservable<number>;
tick$.connect();
import { timer, publishReplay, ConnectableObservable } from 'rxjs';

const tick$ = timer(1000).pipe(
  publishReplay(2)
) as ConnectableObservable<number>;
tick$.connect();

refCount

import { timer, publish, refCount } from 'rxjs';

const tick$ = timer(1000).pipe(
  publish(),
  refCount()
);

Scheduler Argument

Deprecated in v6.5, will be removed in v8. Use scheduled() function instead of scheduler arguments.

Affected Operators

  • from, of, merge, concat
  • startWith, endWith
  • combineLatest

Migration to scheduled

import { of, asyncScheduler } from 'rxjs';

of(1, 2, 3, asyncScheduler).subscribe(console.log);
import { from, asyncScheduler } from 'rxjs';

from([1, 2, 3], asyncScheduler).subscribe(console.log);
import { concat, of, asyncScheduler } from 'rxjs';

concat(
  of('hello'),
  of('world'),
  asyncScheduler
).subscribe(console.log);
import { merge, of, asyncScheduler } from 'rxjs';

merge(
  of(1, 2),
  of(3, 4),
  asyncScheduler
).subscribe(console.log);
import { combineLatest, of, asyncScheduler } from 'rxjs';

combineLatest(
  of('hello'),
  of('world'),
  asyncScheduler
).subscribe(console.log);

ResultSelector Parameter

Deprecated in v6.0, will be removed in v8. Use map operator instead of resultSelector parameter.

Why It Was Deprecated

  1. Increases bundle size for every operator
  2. Can cause memory pressure by retaining values
  3. Same functionality available via map

Affected Operators

  • concatMap, concatMapTo
  • exhaustMap
  • mergeMap, mergeMapTo
  • switchMap, switchMapTo

Migration Examples

import { fromEvent, switchMap, interval } from 'rxjs';

fromEvent(document, 'click').pipe(
  switchMap(
    () => interval(1000),
    (outer, inner) => inner + 1 // resultSelector
  )
).subscribe(console.log);
import { of, mergeMap } from 'rxjs';

of(1, 2, 3).pipe(
  mergeMap(
    x => of(x * 10),
    (outer, inner) => ({ outer, inner }) // resultSelector
  )
).subscribe(console.log);

Array Arguments

Deprecated in v6.5. Pass arrays or objects instead of multiple arguments.

Affected Operators

  • combineLatest
  • forkJoin

Migration Examples

import { forkJoin, of } from 'rxjs';

const odd$ = of(1, 3, 5);
const even$ = of(2, 4, 6);

forkJoin(odd$, even$).subscribe(console.log);
import { combineLatest, of } from 'rxjs';

combineLatest(
  of(1),
  of('a'),
  of(true)
).subscribe(console.log);

Deprecated Operators

concat, merge, zip, race (Pipeable)

The pipeable versions of concat, merge, zip, and race are deprecated. Use the new -With variants.
import { of } from 'rxjs';
import { concat, merge, zip, race } from 'rxjs/operators';

of(1).pipe(concat(of(2))).subscribe();
of(1).pipe(merge(of(2))).subscribe();
of(1).pipe(zip(of(2))).subscribe();
of(1).pipe(race(of(2))).subscribe();

Migration Timeline

1

RxJS v6.4 (2019)

Subscribe arguments deprecated
2

RxJS v6.5 (2019)

  • Scheduler arguments deprecated
  • Array arguments pattern introduced
  • ResultSelector deprecated
3

RxJS v7 (2021)

  • All v6 deprecations still functional
  • toPromise() deprecated
  • Multicasting APIs deprecated
  • New replacement APIs introduced
4

RxJS v8 (Future)

All deprecated APIs will be removed

Quick Reference

Deprecated APIReplacementVersion
toPromise()firstValueFrom() / lastValueFrom()v7 → v8
subscribe(fn, fn, fn)subscribe({ next, error, complete })v6.4 → v8
multicast()connectable() / share()v7 → v8
publish()connectable() / share()v7 → v8
publishBehavior()connectable() with BehaviorSubjectv7 → v8
publishLast()connectable() with AsyncSubjectv7 → v8
publishReplay()connectable() / shareReplay()v7 → v8
refCount()share()v7 → v8
of(..., scheduler)scheduled([...], scheduler)v6.5 → v8
resultSelector parametermap() operatorv6.0 → v8
combineLatest(a, b)combineLatest([a, b])v6.5 → v8
concat operatorconcatWithv7 → v8
merge operatormergeWithv7 → v8
zip operatorzipWithv7 → v8
race operatorraceWithv7 → v8

Additional Resources