DEV Community

Cover image for Signals have no operators. Try these instead
Dario Mannu
Dario Mannu

Posted on • Edited on

Signals have no operators. Try these instead

Signals, one of a few competing reactive primitives in JavaScript land, promised simplicity and performance. Their lack of built-in operators, unlike Observables, has some developers scratching their heads, though.

Observables with map, filter, reduce and many others, excel at composing even the most complex data flows. They can be used to model any problem from user inputs, to async streams with elegance and flexibility.

Signals? They are perceived as familiar and maybe "simpler" to imperative-only programmers, but their minimalism forces you to effectively reinvent an equivalent of each of those operators every time, leading to verbose and error-prone code.

The Power of Composition

Processing a stream of user inputs may look something like this using observables:

const stream = input.pipe(
  map(value => value.toUpperCase()),
  filter(value => value.length > 3),
  scan((acc, val) => acc +val)
);
Enter fullscreen mode Exit fullscreen mode

Using Signals, "reinventing" even an equivalent of something like a basic filter operation becomes interesting at best:

const filtered = new Signal.State(undefined);

const w = new Signal.subtle.Watcher(() => {
  if (sourceSignal.get() == 'something') {
    filtered.set(sourceSignal.get());
  }
});

w.watch(sourceSignal); });
Enter fullscreen mode Exit fullscreen mode

Is the above even correct? Let alone it grows really cumbersome for complex logic, requiring custom functions for every transformation.
What if you need an equivalent of RxJS' distinctUntilChanged? There you go, reinventing it again in your code.

The initial hype around the Signals pattern, praised for its performance, fades quickly when you realise how much it feels like a big step back, at least if you've experienced using Observables before.

Operators for Signals?

What if Signals had an equivalent set of operators? That might help narrowing the gap.

const mappedSignal = map(source, value => value * 2);
const filteredSignal = filter(source, value => value > 10);
Enter fullscreen mode Exit fullscreen mode

A little proof of concept shows how operators could enhance Signals by adding composability and some structure to apply the map/reduce paradigm.

Run on Stackblitz

Conclusion

Observables' operator ecosystem makes them unmatched for reactive programming big or small. Signals, designed to accomodate the needs of imperative frameworks, demand a lot of manual transformations, although you don't get that from propaganda.

Adding operators could make Signals more versatile. We could create whole reactive pipelines the same way as we can do with Observables, but... you might wonder why not just use Observables then, and it would be a totally fair point.

Observables remain the best choice for well-designed rich data flows, but Signals could help filling the reactivity gaps in frameworks whose design doesn't make it possible to use Observables without workarounds.

Have you never missed RxJS-like operators from Signals? What's your experience? Leave a comment below.

Learn More

Top comments (0)