Generated by MidJourney AI

Custom graphics generated by MidJounrey AI

Before getting into the heart of the debate, it’s worth noting that anyone can weigh in on proposed Angular changes. The team invites feedback through public discussions on each sub-RFC. This piece centers on sub-RFC 4.

Signals and sub-RFC 4 — the basics

A quick primer on Angular Signals: they represent a new model for reactivity in Angular, one that aims to simplify state management while offering precise control over when components update.

Sub-RFC 4 focuses on how Signals will mesh with RxJS Observables — the current backbone of reactive patterns in Angular. The proposal is a key step toward a smoother coexistence.

Signals and RxJS — finding common ground

For Angular Signals, interoperability with established RxJS code is a core goal. This matters for both existing applications and the wider ecosystem of libraries.

To that end, sub-RFC 4 outlines two new functions—toObservable and toSignal—as a bridge in either direction. Both APIs live in @angular/core/rxjs-interop. Remember, these are still early proposals.

The toSignal function

Turning an RxJS Observable into an Angular Signal is what toSignal does:

const counter: Signal<number> = toSignal(counter$);
Enter fullscreen mode Exit fullscreen mode

Under the hood, this function subscribes to the Observable and refreshes the Signal’s value on every emission. The subscription is set up right away, and handling cleanup is automatic — Angular terminates the subscription when the surrounding context is torn down.

Setting an initial value

For times when the Observable hasn’t produced a value yet, toSignal accepts a fallback value that stands in for the Signal’s initial state:

const secondsObs = interval(5000);
const seconds = toSignal(secondsObs, 0);
effect(() => {
  console.log(seconds());
});
Enter fullscreen mode Exit fullscreen mode

Handling errors and completion

A Signal encapsulates a single current value and notifies its readers of changes. Observables, by contrast, emit three separate kinds of notifications: next, error, and complete. When the subscription that toSignal manages receives an error notification, that error surfaces the next time the Signal is read — it’s thrown directly. To intercept this, you have options: apply catchError to the Observable before conversion, or use computed on the Signal side to handle it gracefully.

Signals have no equivalent to an Observable’s completion event — there is no “complete” state built in. Still, you can model completion yourself using a separate Signal, or reach for operators like materialize.

The toObservable function

For the inverse conversion, toObservable accepts an Angular Signal and returns an Observable. Internally, subscribing to that Observable triggers an effect, which reads the Signal and forwards each new value along to the subscriber.

const count: Observable<number> = toObservable(mySignal);

Enter fullscreen mode Exit fullscreen mode

The Observable returned by toObservable streams values asynchronously; the underlying effect is what pushes each new Signal value downstream. If you need that initial value without waiting for the next emission cycle, startWith comes in handy:

const obs$ = toObservable(mySignal).pipe(startWith(mySignal()));
Enter fullscreen mode Exit fullscreen mode

Lifecycle behavior and cleanup

With toObservable, the effect doesn’t begin until a subscriber arrives, and it runs for as long as that subscription is active.

That’s a deliberate contrast to toSignal, where the subscription is tied to the creation context and teardown is handled for you.

If you prefer to bind the lifespan of the Observable to a component, it’s easy enough to wire things up manually:

const myValue$ = toObservable(myValue).pipe(takeUntil(this.destroy$))
Enter fullscreen mode Exit fullscreen mode

Conclusion

The intention behind these APIs is to build a practical bridge between RxJS and Signals. Minimizing disruption for existing codebases is a stated priority, so developers can keep using familiar patterns while adopting Signals gradually.

Generated by MidJourney AI

The core of the debate: Signals and Observables

Where the conversation gets lively is around the sub-RFC 4 proposal — in particular, whether a deeper integration should happen. Specifically, should Angular Signals align with widely recognized standards for interoperability, such as Symbol.asyncIterator and Symbol.observable?

Sub-RFC 4 for Angular Signals sparks interesting discussion started by RxJS author — Ben Lesh — figure 3

Ben Lesh’s perspective

Ben Lesh sees merit in building Signals so they slot directly into existing Observable chains. His reasoning is that Signals naturally operate over time, which fits the Observable model well. Adopting these common interop points would give Angular Signals broader applicability beyond the framework itself.

Sub-RFC 4 for Angular Signals sparks interesting discussion started by RxJS author — Ben Lesh — figure 4

Alex Rickabaugh’s counterpoints

On the other side, Alex Rickabaugh acknowledges that the team considered precisely this design, but cites obstacles: Angular Signals have some unique traits and reading them safely in the middle of change propagation is not straightforward.

What’s more, Signals depend on an injection context. That dependency could land as an unexpected burden on developers who use them inside Observable pipelines. Signals aren’t Observables, Alex argues; treating conversions between the two as explicit steps helps keep architecture deliberate and sound.

What the Angular Team Decided

The Angular team has not budged on their decision: neither InteropObservable nor any Subscribable interface will be added to Angular Signals. Even though the framework itself is unchanged for now, the conversation has produced useful takeaways and opened up significant questions about how Signals and Observables will evolve.

Generated by MidJourney AI

Keeping Up with the Discussion

The sub-RFC 4 thread shows just how complex it can be to refine Angular. With the community weighing in on these proposals, ongoing debate is inevitable—and in the end it should lead to a stronger implementation. Following these discussions closely, and jumping in when you have something meaningful to contribute, seems like the right move.


Did You Enjoy the Article?

If so, you may want to check out what I’m doing on Twitter. I’m hosting live Twitter Spaces focused on Angular, featuring GDEs and other industry experts. You can join in live, ask questions, or catch the highlights in short video clips.

Interested? Give me a follow on Twitter @DanielGlejzner — it means a lot. Thanks!