RxJS Interop: toSignal, toObservable, takeUntilDestroyed In short: Signals did not replace RxJS. This is the most common misunderstanding in modern Angular, and acting on it produces real bugs. This lesson draws the line clearly. Angular's own design says so: is a first-class package, and is built on , which still returns observables. What changed is who does which job . The division of work Signals hold the current value of something. Is the panel open, which tab is active, what is in the search box, what is the total. Always readable straight away, no subscription, no cleanup. RxJS handles events arriving over time. Keystrokes that need a pause, a live feed, a request that should cancel the one before it, a retry, two sources that need combining with careful timing. The test: does this need to say anything about time ? Waiting, cancelling, retrying, ordering, buffering — those are all about time, and signals have no words for them. cannot say "wait 300ms." cannot say "cancel the previous one." The other way round: if all you do is hold a value and read it, RxJS is a lot of machinery for that. — from stream to value The most-used function in the package. It replaces the pipe: The subscription is created immediately and cleaned up with the component. There is nothing to write. The starting-value question A signal must always have a value, and an observable may not have produced one yet. So has to give you something at the very start. Four options: is the right choice for a or anything with . It gives you a value that is always there, and it fails loudly during development if that assumption breaks. Reach for it whenever the stream really does produce a value immediately, because it removes a "might be missing" from every type below it. Errors An observable error becomes a throw when you read the signal . There is no error channel on a signal. So for any stream that can fail, handle it before converting: Or use (next lesson), which treats errors as a normal state rather than a crash. — from value to stream The other direction, for when you need time-based operators on something that starts as a signal: Signal in, stream in the middle, signal out. This is the standard shape, and it is exactly what the -that-fetches mistake gets wrong — here cancels the request in flight when a new keystroke arrives, so a slow reply to an old search can never overwrite a newer one. Two details: uses an effect inside, so it produces values on Angular's update cycle rather than the instant you write. And it needs to be created in a component or service, not just anywhere. As of v22 there is also a signals-only : That covers waiting without leaving signals. It does not cover cancelling. Where you need real operator work, is still the tool. This replaces five lines of the same code in every component: Called in a component, it finds what it needs itself. Called elsewhere — in , say — pass it in: is useful on its own for cleanup that has nothing to do with RxJS, and it works in services too : That is the modern replacement for writing purely to clear a timer. What should stay a stream A checklist for "should I convert this?" Keep it RxJS if it involves: waiting for a pause, cancelling work in flight, retrying, live feeds, combining sources with careful timing, buffering, or anything where you care about the sequence of values rather than the latest one. Convert to signals if it is: a holding screen state, a simple transformation of one other value, the pipe used just to show something, or state that was only in RxJS because that is what existed. That last one is most of the conversions in a typical project. A great deal of in Angular apps was never a stream — it was ordinary state wearing RxJS clothes, because before v16 there was nothing else. Those conversions are pure wins. "But I thought Signals replaced RxJS?" This is the big one. Let me take it apart properly. Where the belief comes from. It is not silly. Signals genuinely did replace RxJS for a large share of what RxJS was being used for in Angular apps — holding a current value. When most of the s in a codebase become signals, it feels like a replacement. Why it is wrong. They solve different problems, and Angular's own design says so plainly: is a first-class, actively developed package. You do not build bridges to something you are deleting. still returns observables. It was never converted. exists specifically so you can put an RxJS pipeline inside a resource. exists so you can leave signals when you need to. If signals were a replacement, three of those four would not exist. The precise difference: Signals RxJS --- --- --- Holds The current value Events over time Reading Straight away — Subscribe and wait Understands time? No Yes Can say "wait 300ms"? No Can say "cancel the last one"? No Can say "retry 3 times"? No Number of values Always exactly one Zero, one, or endless What the misunderstanding actually costs. Someone who believes signals replaced RxJS writes this: T…