Angular’s Signals API, both normal signals and writable signals

Leader posted 1 min read

They basically help to manage reactive states—but they serve slightly different purposes.


What is a Signal in Angular?

A signal is a reactive primitive introduced in Angular 16+ to track state changes in a more declarative and efficient way — without requiring Observables or ChangeDetectorRef.


Writable Signal (signal())

It’s the most common type and can be updated directly.

import { signal } from '@angular/core';

const count = signal(0);

// Get value
console.log(count()); // 0

// Set a new value
count.set(1);

// Update with function
count.update(current => current + 1);

Use it when:

  • You need to read and write state.
  • You're managing local component state, like counters, form states, etc.

Read-only Signal (computed() or readonly())

This is a derived signal, typically created using computed() or readonly().

It is not writable directly.

import { signal, computed } from '@angular/core';

const count = signal(2);
const double = computed(() => count() * 2);

console.log(double()); // 4

// double.set(10); ❌ Not allowed (read-only)

If you forcefully convert a writable signal to read-only, you use:

import { readonly } from '@angular/core';

const state = signal('draft');
const readOnlyState = readonly(state);

// readOnlyState.set('published'); ❌ Not allowed

Use it when:

  • You want derived values or read-only state.
  • You want to expose state safely without allowing outside updates.

Summary Table

Feature signal() (Writable Signal) computed() / readonly() (Read-only Signal)
Can update value ✅ Yes ❌ No (derived or locked)
Can be used for state ✅ Yes ✅ As a derived state
Used for input value ✅ Often No direct input
Mutation-safe ⚠️ Needs care ✅ Safe from mutation
Ideal for State you read/write Derived state / exposed state without updates

Example in Angular Component

@Component({
  selector: 'my-counter',
  standalone: true,
  template: `
    <button (click)="increment()">Count: {{ count() }}</button>
    <p>Double: {{ doubleCount() }}</p>
  `
})
export class CounterComponent {
  count = signal(0); // Writable signal

  doubleCount = computed(() => this.count() * 2); // Read-only signal

  increment() {
    this.count.update(c => c + 1);
  }
}
If you read this far, tweet to the author to show them you care. Tweet a Thanks
0 votes

More Posts

Learn to build complete web apps by mastering both frontend and backend development technologies.

Sushant Gaurav - Jan 29

JavaScript Tricks for Efficient Developers and Smart Coding

Mainul - Nov 30, 2024

Leveraging service workers to enhance web app performance and reliability

Sunny - Jun 8

Top Coding Languages to Learn in 2025: Stay Ahead in Tech

Michael Liang - May 15

Web Performance Optimization with NgOptimizedImage in Angular

Sunny - Jun 9
chevron_left