Signals and the RxJS Interop
Signals and RxJS are not a contradiction but complementary


Coming up in version 16 of Angular there are a lot of revolutionary changes, such as signals which will change the way we develop Angular applications from the ground up. They are being described as the new reactive primitive and promise a future without the need of NgZones, such that change detection will be able to run more fine-grained. This will lead to more performant applications and introduces a standard for handling reactivity in Angular.
But hold on a second... What about my beloved RxJS?!
Although both tackle reactivity, signals are meant to be used to correspond to
fine-grained value changes introducing a new way of doing change detection
more locally, rather than traversing the entire component tree checking for
changes. This process is synchronous, which is key deviation from RxJS, cause
RxJS is asynchronous. An observable, although reactive, does not have any
implications on change detection and is therefore not a reactive primitive. A
signal can be thought of as values that change over time for which there is a
producer and a consumer. On the other hand, RxJS is an event stream, where an
observer can react to events.
By this very definition they are not competitive, but instead complementary to
each other. Additionally, the Angular team has put a focus on making the
interoperability between signals and RxJS a piece of cake. So don't worry,
RxJS is not vanishing. Maybe it will be used just a bit less for cases where
it is a bit over-blown, but that is for the better.
Signal to Observable
If you already have a signal and want to create an observable from it which emits whenever the signal produces a new value, than you can use the toObservable function.
readonly searchCriteria = signal('');
readonly result$ = toObservable(this.searchCriteria).pipe(
filter((criteria) => criteria.length > 4),
switchMap((criteria) => this.searchService.search(criteria))
);
Observable to Signal
If yu want to go the other way around and create a signal from an observable, which produces a new value on each emit of the oservable, than you can use the toSignal function.
readonly searchCriteria = signal('');
readonly result$ = toObservable(this.searchCriteria).pipe(
filter((criteria) => criteria.length > 4),
switchMap((criteria) => this.searchService.search(criteria))
);
readonly result = toSignal(this.result$);
Attention! Be careful, that the observable emits a value before the signal is read, because otherwise the signal would throw an error, because it needs to have an initial value. You could either make a BehaviorSubject to a signal, or have a startWith , or you specify an initial value in the toSignal function.
readonly result = toSignal(this.result$, {
initialValue: [] as Result[]
});
Implications
Signals will change a lot in the way we develop Angular applications, including the use of RxJS.
RxJS will not go away, but might decline a bit, because there are new ways of doing reactive synchronous programming in Angular that are simply easier in comparison.
One shift we will likely see it the vanishing of the
async pipe.
In the future whenever an observable would go into the template, there will be a conversion to a signal, such that the fine-grained change detection works.
RxJS will primarily be used in cases where something asynchronous needs to happen on a signal value change.
Some Angular APIs will change and provide signals, such as the Router API for accessing route params, which had to be done with a subscribe on an observable before.
But others like the
HttpClient
won't get signal support because the
HttpClient
by definition is asynchronous and therefore has no need for signals.