<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Amanulla Khan</title>
    <description>The latest articles on DEV Community by Amanulla Khan (@amankhan55).</description>
    <link>https://dev.to/amankhan55</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4025311%2F0c59a89d-ca77-4b42-ab52-c6f978fb6039.jpeg</url>
      <title>DEV Community: Amanulla Khan</title>
      <link>https://dev.to/amankhan55</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/amankhan55"/>
    <language>en</language>
    <item>
      <title>Angular Signals in 2026: From Fundamentals to Architect-Level Patterns</title>
      <dc:creator>Amanulla Khan</dc:creator>
      <pubDate>Sat, 11 Jul 2026 18:38:49 +0000</pubDate>
      <link>https://dev.to/amankhan55/angular-signals-in-2026-from-fundamentals-to-architect-level-patterns-55l5</link>
      <guid>https://dev.to/amankhan55/angular-signals-in-2026-from-fundamentals-to-architect-level-patterns-55l5</guid>
      <description>&lt;p&gt;Angular used to be the framework you apologized for. Too much boilerplate, too much Zone.js magic, too much RxJS ceremony for a checkbox. Somewhere between v16 and v22, that changed. Signals are no longer "a new primitive to learn" — as of &lt;strong&gt;Angular 22 (June 2026)&lt;/strong&gt;, &lt;code&gt;OnPush&lt;/code&gt; is the default change detection strategy, zoneless is the default for new apps, and &lt;strong&gt;Signal Forms and the Resource API are stable&lt;/strong&gt;. Angular is now, by design, a signal-first framework.&lt;/p&gt;

&lt;p&gt;This article covers the full arc: what signals are, how they work internally, how they change your architecture and performance story, how they compare to RxJS, and how to actually migrate a real codebase — plus the interview questions you'll get asked about all of it.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. The fundamentals
&lt;/h2&gt;

&lt;p&gt;A signal is a wrapper around a value that knows who's reading it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;computed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;effect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;          &lt;span class="c1"&gt;// writable signal&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;doubled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;computed&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;count&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// derived, read-only, memoized&lt;/span&gt;

&lt;span class="nf"&gt;effect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`count is now &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;count&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// reruns when count changes&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three primitives, three jobs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;signal()&lt;/code&gt;&lt;/strong&gt; — holds state, read by calling it as a function, written via &lt;code&gt;.set()&lt;/code&gt; / &lt;code&gt;.update()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;computed()&lt;/code&gt;&lt;/strong&gt; — derives state. Lazy and memoized: it only recalculates when a dependency actually changed &lt;em&gt;and&lt;/em&gt; someone reads it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;effect()&lt;/code&gt;&lt;/strong&gt; — runs side effects (logging, syncing to localStorage, imperative DOM work) in response to signal changes. Not for driving template state — if you're setting another signal inside an effect to keep it "in sync," you probably wanted &lt;code&gt;computed()&lt;/code&gt; or &lt;code&gt;linkedSignal()&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Angular 20 graduated all of these — plus signal-based &lt;code&gt;input()&lt;/code&gt;, &lt;code&gt;model()&lt;/code&gt;, and signal queries (&lt;code&gt;viewChild&lt;/code&gt;, &lt;code&gt;contentChild&lt;/code&gt;) — to stable. If you're on 20+, this is no longer "the new way," it's &lt;em&gt;the&lt;/em&gt; way for new components.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-user-card&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;standalone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`...`&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserCardComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;userId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;required&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;       &lt;span class="c1"&gt;// signal-based @Input&lt;/span&gt;
  &lt;span class="nx"&gt;isActive&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                 &lt;span class="c1"&gt;// two-way bindable signal&lt;/span&gt;
  &lt;span class="nx"&gt;header&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;viewChild&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ElementRef&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;header&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// signal-based @ViewChild&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. How signals actually work (the internals interviewers ask about)
&lt;/h2&gt;

&lt;p&gt;Signals implement a &lt;strong&gt;push-pull reactive model&lt;/strong&gt;, and this distinction is the single most-tested concept in interviews:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Push&lt;/strong&gt;: when a writable signal changes, it immediately (synchronously) notifies its direct consumers that they're "dirty." This is cheap — it's just a flag flip, not a recomputation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pull&lt;/strong&gt;: the actual recomputation only happens lazily, when something &lt;em&gt;reads&lt;/em&gt; the dirty signal — inside a &lt;code&gt;computed()&lt;/code&gt; or during change detection when a template reads it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is why signals are &lt;strong&gt;glitch-free&lt;/strong&gt;. In a naive push-based system, if &lt;code&gt;computed&lt;/code&gt; &lt;code&gt;C&lt;/code&gt; depends on both &lt;code&gt;A&lt;/code&gt; and &lt;code&gt;B&lt;/code&gt;, and you update &lt;code&gt;A&lt;/code&gt; then &lt;code&gt;B&lt;/code&gt; in the same tick, &lt;code&gt;C&lt;/code&gt; might recompute twice and briefly observe an inconsistent intermediate state. Angular's dependency graph batches this: &lt;code&gt;C&lt;/code&gt; is marked dirty once, and only recomputes once, on next read, with both updates applied.&lt;/p&gt;

&lt;p&gt;Under the hood, each signal maintains a version counter. A &lt;code&gt;computed()&lt;/code&gt; caches its last value and the versions of the signals it read last time. On read, it compares versions; if nothing upstream changed, it returns the cached value without re-executing the function — that's the memoization.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dependency tracking is automatic and dynamic.&lt;/strong&gt; There's no subscribe/unsubscribe. &lt;code&gt;computed()&lt;/code&gt; and &lt;code&gt;effect()&lt;/code&gt; track &lt;em&gt;whatever signals were actually read during their last execution&lt;/em&gt; — so a conditional read (&lt;code&gt;isAdmin() ? adminData() : userData()&lt;/code&gt;) only creates a dependency on the branch that actually executed. Change the condition, and the dependency set changes on the next run. This is structurally similar to Vue's reactivity system and SolidJS, and it's a fair comparison to bring up in an interview.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Change detection implications (this is the part senior candidates get wrong)
&lt;/h2&gt;

&lt;p&gt;Pre-signals Angular used Zone.js to monkey-patch async APIs (&lt;code&gt;setTimeout&lt;/code&gt;, &lt;code&gt;addEventListener&lt;/code&gt;, promises) so it could guess &lt;em&gt;something might have changed&lt;/em&gt; and run change detection on the whole component tree from the root. It works, but it's a blunt instrument — you get checks you don't need, and debugging "why did CD run" is miserable.&lt;/p&gt;

&lt;p&gt;Signals flip this to &lt;strong&gt;explicit, targeted notification&lt;/strong&gt;. A component reading a signal in its template gets automatically marked for a targeted check when that signal changes — no zone patching, no tree-wide guessing.&lt;/p&gt;

&lt;p&gt;As of &lt;strong&gt;Angular 22, &lt;code&gt;OnPush&lt;/code&gt; is the default &lt;code&gt;changeDetection&lt;/code&gt; strategy&lt;/strong&gt; for new components (the old "Default" strategy is renamed &lt;code&gt;Eager&lt;/code&gt; and deprecated). Combined with zoneless (stable default since Angular 21), the practical effect is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No Zone.js in your bundle (smaller payload, faster startup).&lt;/li&gt;
&lt;li&gt;Change detection runs only for components whose signals actually changed, not the whole tree.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;markForCheck()&lt;/code&gt; calls scattered through legacy code become mostly unnecessary — signals do it for you.&lt;/li&gt;
&lt;li&gt;Non-signal mutations (mutating a plain array/object field that CD can't observe) silently stop working correctly under zoneless. This is the #1 zoneless migration bug — reaching into &lt;code&gt;this.items.push(x)&lt;/code&gt; on a plain field instead of &lt;code&gt;this.items.update(arr =&amp;gt; [...arr, x])&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Interview question you should be able to answer cold&lt;/strong&gt;: &lt;em&gt;"Why does OnPush + signals outperform Zone.js-based default CD, and what's the one thing that breaks silently when you go zoneless?"&lt;/em&gt; Answer: targeted vs. tree-wide checks, and the answer to the second half is exactly the mutation issue above.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. &lt;code&gt;linkedSignal&lt;/code&gt; and &lt;code&gt;resource()&lt;/code&gt; — the pieces that make signals a full state system
&lt;/h2&gt;

&lt;p&gt;Two APIs turn signals from "a better &lt;code&gt;@Input&lt;/code&gt;" into an actual state-management layer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;linkedSignal&lt;/code&gt;&lt;/strong&gt; (stable since Angular 19) is a writable signal that resets itself when a source signal changes — the classic "selected item resets when the list changes" problem, without an &lt;code&gt;effect()&lt;/code&gt; fighting your &lt;code&gt;computed()&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;b&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;c&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;selected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;linkedSignal&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt; &lt;span class="c1"&gt;// resets to items()[0] whenever items() changes&lt;/span&gt;
&lt;span class="nx"&gt;selected&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;b&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// but user can still override it locally until items() changes again&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;code&gt;resource()&lt;/code&gt; / &lt;code&gt;httpResource()&lt;/code&gt;&lt;/strong&gt; (stable in Angular 22) replace the "subscribe in ngOnInit, manage loading/error flags by hand" pattern with a declarative async primitive:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;userId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;required&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;userResource&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;httpResource&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;`/api/users/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// userResource.value(), userResource.status(), userResource.error(), userResource.isLoading()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Change &lt;code&gt;userId&lt;/code&gt;, and the resource automatically re-fetches — no manual &lt;code&gt;switchMap&lt;/code&gt;, no subscription teardown. As of Angular 21.2, &lt;code&gt;snapshot()&lt;/code&gt; lets you derive a &lt;em&gt;new&lt;/em&gt; resource from an existing one (e.g., a filtered/paginated view) without touching the original fetch logic — genuinely useful for enterprise dashboards with shared base data and multiple derived views.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Signals vs. RxJS — pick the right tool, not a religion
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Signals&lt;/th&gt;
&lt;th&gt;RxJS&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Best for&lt;/td&gt;
&lt;td&gt;Synchronous UI state, derived values, template bindings&lt;/td&gt;
&lt;td&gt;Streams over time: websockets, typeahead debounce, complex event composition&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mental model&lt;/td&gt;
&lt;td&gt;Pull-based, glitch-free, always has a current value&lt;/td&gt;
&lt;td&gt;Push-based, operators, may never emit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Boilerplate&lt;/td&gt;
&lt;td&gt;Minimal — no subscribe/unsubscribe&lt;/td&gt;
&lt;td&gt;Higher — operators, &lt;code&gt;takeUntilDestroyed&lt;/code&gt;, memory-leak discipline&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Composability&lt;/td&gt;
&lt;td&gt;Growing (&lt;code&gt;linkedSignal&lt;/code&gt;, &lt;code&gt;resource&lt;/code&gt;) but narrower&lt;/td&gt;
&lt;td&gt;Extremely rich (60+ operators)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Angular's stance (2026)&lt;/td&gt;
&lt;td&gt;Default for component state&lt;/td&gt;
&lt;td&gt;Still first-class for genuine async streams&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The Angular team has been explicit: &lt;strong&gt;RxJS isn't going away.&lt;/strong&gt; &lt;code&gt;toSignal()&lt;/code&gt; / &lt;code&gt;toObservable()&lt;/code&gt; interop exists precisely because you'll keep both in the same codebase — RxJS for a websocket-driven live feed, signals for the UI state that renders it. Treat "should I use signals or RxJS" the way you'd treat "should I use a &lt;code&gt;Map&lt;/code&gt; or an array" — depends on the shape of the problem, not on which one is newer.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Migrating a real codebase (NgModules + RxJS → Signals)
&lt;/h2&gt;

&lt;p&gt;Don't do a big-bang rewrite. The Angular team's own guidance, and what holds up in practice on large enterprise apps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Upgrade to a supported version first.&lt;/strong&gt; Combining a multi-version jump with a signals migration is the most common way these efforts stall out — get current, &lt;em&gt;then&lt;/em&gt; modernize.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Convert leaf components first.&lt;/strong&gt; Presentational components with &lt;code&gt;@Input()&lt;/code&gt;/&lt;code&gt;@Output()&lt;/code&gt; are low-risk: swap to &lt;code&gt;input()&lt;/code&gt;/&lt;code&gt;output()&lt;/code&gt;, verify, move up the tree.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Replace &lt;code&gt;BehaviorSubject&lt;/code&gt;-as-state with &lt;code&gt;signal()&lt;/code&gt;.&lt;/strong&gt; If a &lt;code&gt;BehaviorSubject&lt;/code&gt; exists purely to hold "current value UI reads," it's a signal in disguise.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep genuine streams as Observables&lt;/strong&gt;, bridge with &lt;code&gt;toSignal()&lt;/code&gt; at the template boundary.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Turn on &lt;code&gt;OnPush&lt;/code&gt; explicitly before you touch signals&lt;/strong&gt;, so you isolate "did this break because of CD strategy" from "did this break because of signals."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zoneless last.&lt;/strong&gt; It's the biggest behavioral change (silent mutation bugs) — do it once signals are already load-bearing in the app.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  7. Enterprise example: a filtered order dashboard
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-order-dashboard&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;standalone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;changeDetection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ChangeDetectionStrategy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OnPush&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
    &amp;lt;input [ngModel]="statusFilter()" (ngModelChange)="statusFilter.set($event)" /&amp;gt;
    @if (ordersResource.isLoading()) { &amp;lt;app-spinner /&amp;gt; }
    @for (order of filteredOrders(); track order.id) {
      &amp;lt;app-order-row [order]="order" /&amp;gt;
    }
  `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OrderDashboardComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;customerId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;required&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;statusFilter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;signal&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;all&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pending&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;shipped&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;all&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;ordersResource&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;httpResource&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;`/api/customers/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;customerId&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="s2"&gt;/orders`&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;filteredOrders&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;computed&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;orders&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ordersResource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;value&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;statusFilter&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;all&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;orders&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;o&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;effect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// side effect only — analytics, not state&lt;/span&gt;
      &lt;span class="nx"&gt;analytics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;track&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dashboard_filtered&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;statusFilter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice what's &lt;em&gt;absent&lt;/em&gt;: no &lt;code&gt;ngOnInit&lt;/code&gt; subscription, no &lt;code&gt;loading&lt;/code&gt;/&lt;code&gt;error&lt;/code&gt; boolean fields, no manual unsubscribe, no &lt;code&gt;markForCheck()&lt;/code&gt;. Changing &lt;code&gt;customerId()&lt;/code&gt; re-fetches automatically; changing &lt;code&gt;statusFilter()&lt;/code&gt; re-filters automatically; both are independently cached and only recompute what actually needs it.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Common anti-patterns
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Effects that write signals to "sync" state.&lt;/strong&gt; If &lt;code&gt;effect()&lt;/code&gt; exists only to call &lt;code&gt;.set()&lt;/code&gt; on another signal, use &lt;code&gt;computed()&lt;/code&gt; (or &lt;code&gt;linkedSignal()&lt;/code&gt; if it needs local override capability) instead.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reading a signal outside a reactive context and expecting reactivity.&lt;/strong&gt; Calling &lt;code&gt;count()&lt;/code&gt; in a regular method gives you a snapshot, not a subscription — reactivity only happens inside &lt;code&gt;computed&lt;/code&gt;, &lt;code&gt;effect&lt;/code&gt;, or a template.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mutating instead of replacing&lt;/strong&gt; (&lt;code&gt;array.push()&lt;/code&gt; vs &lt;code&gt;.update(a =&amp;gt; [...a, x])&lt;/code&gt;) — silently breaks under zoneless/OnPush since the reference never changes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Overusing &lt;code&gt;effect()&lt;/code&gt; for cross-component communication&lt;/strong&gt; instead of a shared injectable signal/service — reintroduces the debugging pain signals were meant to remove.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  9. Interview questions to be ready for
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Explain the push-pull model and why it makes signals glitch-free.&lt;/li&gt;
&lt;li&gt;What's the practical difference between &lt;code&gt;computed()&lt;/code&gt; and &lt;code&gt;effect()&lt;/code&gt;, and when would using one instead of the other cause a bug?&lt;/li&gt;
&lt;li&gt;Why does OnPush change detection pair naturally with signals, and what breaks when you combine plain-object mutation with zoneless CD?&lt;/li&gt;
&lt;li&gt;How does dynamic dependency tracking work, and what happens to a computed's dependency list when a conditional branch changes?&lt;/li&gt;
&lt;li&gt;When would you &lt;em&gt;still&lt;/em&gt; reach for RxJS over signals in a signals-first Angular 22 app?&lt;/li&gt;
&lt;li&gt;What does &lt;code&gt;linkedSignal&lt;/code&gt; solve that a plain &lt;code&gt;computed()&lt;/code&gt; can't?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  10. Challenge exercise
&lt;/h2&gt;

&lt;p&gt;Build a typeahead search component using &lt;code&gt;httpResource()&lt;/code&gt; and &lt;code&gt;linkedSignal()&lt;/code&gt;: a &lt;code&gt;signal&amp;lt;string&amp;gt;()&lt;/code&gt; for the raw query, a &lt;code&gt;computed()&lt;/code&gt; or &lt;code&gt;linkedSignal()&lt;/code&gt; for a debounced/trimmed version (hint: you'll actually want RxJS's &lt;code&gt;debounceTime&lt;/code&gt; here via &lt;code&gt;toSignal(toObservable(query).pipe(debounceTime(300)))&lt;/code&gt; — a good exercise in knowing exactly where the signals/RxJS boundary should sit), and a &lt;code&gt;resource()&lt;/code&gt; that re-fetches on the debounced value. Add a &lt;code&gt;linkedSignal&lt;/code&gt; for "selected result" that resets whenever the result list changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing thought
&lt;/h2&gt;

&lt;p&gt;Signals aren't a syntax swap for &lt;code&gt;@Input()&lt;/code&gt; — they're Angular's answer to "how do we know exactly what changed, without guessing." That answer now shapes change detection defaults, forms, async data fetching, and DI. If you're prepping for a senior/architect role, the framework-trivia questions ("what's the syntax for &lt;code&gt;computed&lt;/code&gt;") are table stakes; the questions that actually separate candidates are about the &lt;em&gt;reactive graph&lt;/em&gt; — push vs. pull, dependency tracking, and where the signals/RxJS boundary should sit in a real system.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>typescript</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
