⚡ Signals

Angular 17's reactive primitives — signal(), computed(), and effect()

About This Feature

Signals are Angular's new reactive primitive (stable in v17). Unlike RxJS, signals use a simpler synchronous API that's always readable. Angular uses signals to enable fine-grained change detection without Zone.js.

  • signal(value) — creates a writable reactive value
  • computed(() => ...) — derives a read-only signal from other signals
  • effect(() => ...) — runs a side effect when signals change
  • Read a signal by calling it: mySignal()
  • Write with .set() or .update(fn)

Code Example

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

// signal() — writable reactive value
counter = signal(0);

// Read:   counter()
// Write:  counter.set(5)
//         counter.update(n => n + 1)

// computed() — derived, read-only signal
doubleCounter = computed(() => this.counter() * 2);
// Auto-updates whenever counter changes

// effect() — runs as a side effect
constructor() {
  effect(() => {
    // Runs whenever counter() changes
    console.log('Counter:', this.counter());
  });
}

// Signals in objects (shopping cart)
cart = signal<CartItem[]>([]);

cartTotal = computed(() =>
  this.cart().reduce((sum, item) => sum + item.price * item.qty, 0)
);

addToCart(product: Product) {
  this.cart.update(items => {
    const existing = items.find(i => i.id === product.id);
    if (existing) {
      return items.map(i => i.id === product.id
        ? { ...i, qty: i.qty + 1 } : i);
    }
    return [...items, { ...product, qty: 1 }];
  });
}

Live Demo

signal() + computed() + effect()

counter() = 0computed: 0
[effect] counter = 0

Shopping Cart   0 items  Total: $0.00

Angular Book

$29.99

TypeScript Course

$49.99

RxJS Guide

$19.99

NgRx Handbook

$39.99

Cart is empty — add some products!