Linked Signals — DIY
How to use linkedSignals in < Angular 19 projects
Linked signals — one of the shiny new features introduced in Angular 19 — are fantastic. They’re the kind of addition that makes you go, “Wait, why didn’t we have this earlier?” If you’re curious to explore all the details, feel free to check out my dedicated article on linked signals. It goes into the what, why, and how.
But if you’re not in the mood for a deep dive right now, no problem. Here’s the TL;DR: linked signals are basically writable computeds. That’s probably the easiest way to think about them. You get the reactivity of a computed signal, but with the bonus of being able to update it directly.
Now, with that quick context out of the way, let’s look at a scenario that puts this idea into action. What we’re going to explore now is a scenario where we have a computed signal called baz
. This computed depends on two other signals: an input signal named foo
, and another signal called bar
.
In code, it looks a little something like this:
foo = input.required<string>();
bar = signal('bar value');
baz = computed(() => `${this.foo()}-${this.bar()}`);
Now imagine that, for whatever reason, we want to update baz
at some later point. No big deal, right? Normally, we’d just call .set()
or .update()
on a signal and be done with it.
But here’s the catch: baz
is a computed signal—and computed signals are read-only. That means we can't just write to it directly.
Enter linked signals. 🦸♂️
foo = input.required<string>();
bar = signal('bar value');
baz = linkedSignal(() => `${this.foo()}-${this.bar()}`);
handleSomeInteraction(){
this.baz.set('updated value');
}
Using a linkedSignal
solves our problem nicely: it still reacts to changes like a computed, but we also get the power to write into it directly. The best of both worlds.
Everything’s great and awesome — if you’re working in an Angular 19 SPA.
But let’s be honest: many enterprise projects aren’t quite there yet and still use earlier Angular versions. That was exactly the situation I found myself in. I wanted the benefits of a linked signal, but I couldn’t use the real linkedSignal
API from Angular because… well, our project was not on Angular 19.
So I thought to myself: Can I fake it? Can I build a DIY linked signal without the official API?
Turns out… yes, yes you can.
Now here’s what I came up with:
// TODO: replace this with linkedSignal once we are on Angular 19
linkedSignalMock = <T>(callback: () => T) => {
const value = signal<T | undefined>(undefined);
effect(() => {
value.set(callback());
}, {
allowSignalWrites: true
});
return value;
};
Note that the
allowSignalWrites
flag is no longer necessary in newer Angular versions.
So here’s the workaround: we create a function that accepts a generic for proper type support, along with a callback function as its argument. Inside that function, we create a regular writable signal to hold the value.
Then, with the help of an effect
, we listen for changes in any signals used inside the callback. Whenever one of them changes, we update our writable signal accordingly.
In the end, we return that writable signal — voilà, a homegrown version of linkedSignal
, compatible even with pre-Angular 19 projects.
Of course, the ideal solution is to stay up to date with the latest Angular version. The Angular CLI has come a long way and makes updating much smoother than it used to be. But let’s be real: that’s not always possible. Sometimes feature development takes priority, or you’re dealing with a more complex enterprise setup where upgrades require careful planning (and several cups of coffee).
In those cases, I hope this little workaround helps you bridge the gap.
And hey — if you want to really dive into Angular Signals and level up your reactive game, check out my new book on Angular Signals. It’s packed with insights, patterns, and pro tips to help you (and your team) take your project to the next level.