Angular Signals make reactive state much easier to reason about.
Still, many developers mix up two APIs: computed() and linkedSignal().

They both react to change — but they solve different problems.

1) computed(): derived, read-only values

Use computed() when a value is purely calculated from other signals (think Excel formula).

Key traits:

  • automatically recalculates when dependencies change
  • cannot be manually set with .set()
  • ideal for UI display values, totals, filters, and status labels

Example:

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

const price = signal(120);
const vat = signal(0.19);

const grossPrice = computed(() => price() * (1 + vat()));

console.log(grossPrice()); // 142.8
price.set(200);
console.log(grossPrice()); // 238

2) linkedSignal(): derived, but editable

Use linkedSignal() when a value comes from a source signal but should still be editable locally (for example, form draft state).

Typical scenario:

  • selected entity changes (e.g., another user)
  • input field should initialize from that source
  • user can edit locally
  • when source changes, local signal can resync meaningfully
Practical Example: “Edit Selected User”

Imagine you have a selected user and a name input field.

  • With computed(), the name is display-only.
  • With linkedSignal(), you get an editable draft that can still follow source changes.
import { signal, computed, linkedSignal } from '@angular/core';

type User = { id: number; name: string };

const users = signal<User[]>([
  { id: 1, name: 'Anna' },
  { id: 2, name: 'Ben' },
]);

const selectedUserId = signal(1);

const selectedUser = computed(() =>
  users().find(u => u.id === selectedUserId()) ?? null
);

// Read-only derived display value
const upperCaseName = computed(() =>
  selectedUser()?.name.toUpperCase() ?? ''
);

// Editable value linked to selectedUser
const editableName = linkedSignal<string | null>({
  source: selectedUser,
  computation: (user) => user?.name ?? null
});

// --- Usage ---
// initial: "Anna"
console.log(editableName());

// user types in an input:
editableName.set('Anna (Draft)');
console.log(editableName()); // "Anna (Draft)"

// selection changes to Ben:
selectedUserId.set(2);

// linked signal can derive again from the new source
console.log(editableName()); // typically "Ben"

Note: Exact resync behavior can vary slightly by Angular version/options, but the core idea stays the same: locally editable + source-linked.

Why not just use computed() everywhere?

Because computed() is intentionally strict:
it guarantees pure derivation and prevents local mutation.

That’s excellent for consistency — but not for temporary UI edits where users type intermediate values.

Practical Rule of Thumb
  • Use computed() for pure derived values.
  • Use linkedSignal() for source-initialized values that also need local edits.

By Shabazz

Software Engineer, MCSD, Web developer & Angular specialist , BizDevOps

Leave a Reply

Your email address will not be published. Required fields are marked *