Chapter 10.2โ˜• 15 min read

Computed Signals

Computed signals are read-only signals that derive their value from other signals. When any dependency changes, the computed signal automatically recalculates.

01What is a Computed Signal

A computed signal is a read-only signal whose value is derived from other signals. Like an Excel formula โ€” when input cells change, the formula result updates automatically.

"Computed = calculator โ€” input badlo toh output apne aap badal jayega."

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

const firstName = signal('Hyderabadi');
const lastName = signal('Biryani');

// Computed signal โ€” auto-updates when firstName or lastName change
const fullName = computed(() => `${firstName()} ${lastName()}`);

console.log(fullName()); // 'Hyderabadi Biryani'

firstName.set('Chennai');
console.log(fullName()); // 'Chennai Biryani' โ€” auto-updated!

Key properties of computed:

  • Read-only โ€” you cannot .set() or .update() a computed signal. It only reads from its dependencies.
  • Lazy โ€” only recalculates when someone reads the value (or when used in template/effect).
  • Cached โ€” stores the last computed value. If dependencies haven't changed, returns cached value instantly.
  • Automatic dependency tracking โ€” Angular automatically tracks which signals are read inside the computed function.
02Creating Computed Signals

Creating a computed signal is simple โ€” call computed() with a function that reads other signals.

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

// Source signals
price = signal(250);
quantity = signal(2);
discountPercentage = signal(10);

// Derived values โ€” computed signals
total = computed(() => price() * quantity());
discountAmount = computed(() => total() * discountPercentage() / 100);
grandTotal = computed(() => total() - discountAmount());

console.log(grandTotal()); // 450 (500 - 50)

Angular automatically tracks which signals you read inside computed(). When any of those signals change, the computed value is marked as "dirty" โ€” it will recalculate the next time someone reads it.

"computed = formula โ€” dependencies automatically track hoti hai."

TypeScript inference:

price = signal(250); // Signal<number>
total = computed(() => price() * quantity()); // Computed<number>

name = signal('Biryani');
uppercase = computed(() => name().toUpperCase()); // Computed<string>

isReady = signal(false);
message = computed(() => isReady() ? 'Ready!' : 'Loading...'); // Computed<string>
03Computed with Complex Logic

Computed signals can handle any transformation logic โ€” filtering, mapping, reducing, sorting.

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

// Source data
biryanis = signal<Biryani[]>([
  { id: 1, name: 'Chicken Biryani', price: 250, category: 'Non-Veg' },
  { id: 2, name: 'Mutton Biryani', price: 350, category: 'Non-Veg' },
  { id: 3, name: 'Veg Biryani', price: 200, category: 'Veg' },
  { id: 4, name: 'Egg Biryani', price: 220, category: 'Non-Veg' },
]);

selectedCategory = signal('All');

// Computed: filter by category
filteredBiryanis = computed(() => {
  const category = selectedCategory();
  return category === 'All'
    ? biryanis()
    : biryanis().filter(b => b.category === category);
});

// Computed: total price
totalPrice = computed(() =>
  filteredBiryanis().reduce((sum, b) => sum + b.price, 0)
);

// Computed: average price
avgPrice = computed(() =>
  biryanis().length > 0
    ? Math.round(biryanis().reduce((s, b) => s + b.price, 0) / biryanis().length)
    : 0
);

// Computed: sorted by price
sortedByPrice = computed(() =>
  [...biryanis()].sort((a, b) => a.price - b.price)
);

"Jitna complex ho sake โ€” computed handle karega. Filter, map, reduce โ€” sab kuch."

Performance note: Computed signals cache their results. If dependencies haven't changed, the computation does NOT re-run โ€” it returns the cached value. This makes them efficient even with expensive operations.

04Computed Chain

Computed signals can form chains โ€” one computed depends on another, which depends on another.

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

// Base signals
price = signal(500);      // Base price per item
quantity = signal(2);     // Quantity

// Level 1 computed
subtotal = computed(() => price() * quantity()); // 500 ร— 2 = 1000

// Level 2 computed โ€” depends on Level 1
tax = computed(() => subtotal() * 0.05);         // 5% tax = 50

// Level 3 computed โ€” depends on Level 2
total = computed(() => subtotal() + tax());      // 1000 + 50 = 1050

// When price changes:
price.set(600);
// Automatically: subtotal = 1200 | tax = 60 | total = 1260

"Chain = domino effect โ€” ek gira toh sab girte hai, magar Angular sirf wahi recompute karta hai jo actually change hua."

Smart recomputation: Angular uses a dependency graph. When a base signal changes, Angular knows EXACTLY which computed signals depend on it and only recalculates those. Unaffected branches are skipped.

// If price changes:
// โœ“ subtotal recalculates (depends on price)
// โœ“ tax recalculates (depends on subtotal โ€” which changed!)
// โœ“ total recalculates (depends on tax โ€” which changed!)

// But if category filter changes:
// โœ“ filteredBiryanis recalculates
// โœ“ totalPrice recalculates
// โœ— avgPrice stays cached (no dependency on filter)
// โœ— sortedByPrice stays cached
05Computed vs Pipe vs Method

There are three ways to derive values in Angular templates. Computed is almost always the best choice.

MethodCached?Re-runsBest for
computed()โœ… YesOnly when dependencies changeDerived state
Pure Pipeโœ… YesWhen input reference changesTransformations in templates
MethodโŒ NoEvery change detection cycleEvent handlers only
// โŒ BAD โ€” Method called in template runs EVERY CD cycle
get fullName() { return this.first() + ' ' + this.last(); }
// Template: {{ fullName }}  โ† runs 100s of times!

// โš ๏ธ OK โ€” Pipe runs when input reference changes
// {{ value | myPipe }}  โ† only when 'value' changes

// โœ… BEST โ€” Computed runs ONLY when dependencies change
fullName = computed(() => this.first() + ' ' + this.last());
// Template: {{ fullName() }}  โ† cached, efficient

"Computed = smart (cache), Pipe = medium, Method = dumb (always runs)."

Rule of thumb:

  • Need derived state from signals? โ†’ computed()
  • Need to transform data in template? โ†’ Pipe (or computed if already a signal)
  • Need an action on button click? โ†’ Method (not for display)

Key Takeaways

  • โœ… computed() derives value from other signals โ€” like Excel formula
  • โœ… Read-only โ€” no .set() or .update(), only reading with ()
  • โœ… Auto-tracks dependencies โ€” reads signals inside computed function
  • โœ… Cached โ€” returns cached value if dependencies haven't changed
  • โœ… Chainable โ€” computed depends on computed, forms dependency graph
  • โœ… Better than methods โ€” computed only re-runs on dependency change
Course Search
Search across all chapters & stages
๐Ÿ“–

Search the course

Type any topic โ€” branching, stash, rebase, hooks โ€” and jump straight to that chapter.

merge branchesgit stashundo commitrebase