DEV Community

Glib Zaycev
Glib Zaycev

Posted on

How to create simple Angular signal() in JS

Hey there!

So recently I was playing with Angular signals and noticed that I didn't really understand how exactly this language construction works:

public counter = signal(0);

// Then you use it like that in the template.

{{ counter() }}

// But also work with it like that:

counter.update((count) => count + 1)
Enter fullscreen mode Exit fullscreen mode

Although I've been working with JS for years, for some reason I'd never seen such a way to use functions before until I tried signals.

This is pretty basic JS functionality, and I will show you in super simple example how exactly it works.

You'll learn

  • What JS functions really are
  • How angular signals are implemented

JS Functions

So a quick note: functions in JS are not exactly functions; they are function-objects. Functions are objects with internal, hidden [[Call]] and [[Contruct]] methods, and they basically make an object a function.

But it is still an object, and this is exactly how we can achieve the functionality that we have in signals.

I think it's a rather interesting feature of the language. But I am generally ok with any weirdness (that JS supplies in huge volumes), so you can draw your own conclusions.

Implementing signal

We are not going to dive deep into how exactly angular signals are really implemented, but we'll create very simple, basic functionality for them. First, we just create a function:

function signal(value) {

}
Enter fullscreen mode Exit fullscreen mode

To make it look exactly like an angular signal. As you remember, we put signal into a variable by calling it like that:

const counter = signal(0);
Enter fullscreen mode Exit fullscreen mode

And after that, we can either call counter or update it. That means we, for first, should make the signal function return another function:

function signal(value) {
  function caller() {
    return value;
  }
  
  return caller;
}
Enter fullscreen mode Exit fullscreen mode

I called it caller for whatever reason that popped up in my mind at the moment of writing that code. And now the final stroke: using the nature of JS function objects to make counter have mixed behavior:

function signal(value) {
  function caller() {
    return value;
  }
  
  caller.set = (newValue) => value = newValue;
  caller.update = (fn) => value = fn(value);
  
  return caller;
}
Enter fullscreen mode Exit fullscreen mode

And here we are, utilizing the hybrid nature of JS functions.

You can see that we are clearly assigning properties to the caller function as if it were an object.

We've added set and update callbacks to the caller function. Now, when the signal is initialized, we always have the option to call those callbacks or the signal itself.

  • set method allows direct updating of the value.
  • update method lets us do the same but using a callback, passed as a parameter.
// getting the signal value
counter();

// updating signal value
counter.set(42);
// or
counter.update(c => c + 1);
Enter fullscreen mode Exit fullscreen mode

Angular Signals is a very powerful and well-thought-out interface; it is much more complicated and flexible, than our implementation. But it still uses a similar approach because there is always a limiting factor in language possibilities.

However, now you know how to utilize the hybrid nature of JS functions in your everyday routine.

Hopefully you learned something new and it was helpful.

Thank you!

Top comments (0)