<?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: Art Stesh</title>
    <description>The latest articles on DEV Community by Art Stesh (@artstesh).</description>
    <link>https://dev.to/artstesh</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2895201%2F7abb7a4b-789f-4c90-aecf-190a6b87227f.png</url>
      <title>DEV Community: Art Stesh</title>
      <link>https://dev.to/artstesh</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/artstesh"/>
    <language>en</language>
    <item>
      <title>Step Five into RxJS: Error Handling</title>
      <dc:creator>Art Stesh</dc:creator>
      <pubDate>Sat, 24 May 2025 14:00:00 +0000</pubDate>
      <link>https://dev.to/artstesh/step-five-into-rxjs-error-handling-51g1</link>
      <guid>https://dev.to/artstesh/step-five-into-rxjs-error-handling-51g1</guid>
      <description>&lt;p&gt;You've encountered those "fun" stories where a developer finishes a task, it passes testing, goes to production, and&lt;br&gt;
then meets an unexpected failure of some minor API method, bringing down the entire app so users see only a blank&lt;br&gt;
screen?&lt;/p&gt;

&lt;p&gt;I got too close to them back in the day... Honestly, RxJS streams are excellent teachers — you won’t want to repeat&lt;br&gt;
their lessons. What do they teach us? First and foremost: don’t trust external sources. You control neither the server&lt;br&gt;
connection nor the API service, so you have no grounds to blindly trust them or expect flawless operation.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If your backend has five-nines availability (an excellent result!), it’s still down for a few minutes a year. Failures&lt;br&gt;
happen to all systems.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Typical Newbie Scenarios&lt;/strong&gt;
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Ghost Data&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getData&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// What if data === undefined?&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Silent Crash&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;combineLatest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;loadUsers&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="nf"&gt;loadProducts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// If this fails — everything stops&lt;/span&gt;
&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Domino Effect&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;switchMap&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Observable&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="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error!&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="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// On error, the entire stream crashes, data stops updating&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;blockquote&gt;
&lt;p&gt;“A good developer writes code. A great one anticipates how it will break.”&lt;br&gt;&lt;br&gt;
— Unknown Architect*&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Basic Error Handling Operators: Your "First Aid Kit" (Relevant for RxJS 7.8+)
&lt;/h2&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;&lt;code&gt;catchError&lt;/code&gt;: The Digital First Aid&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  How It Works
&lt;/h4&gt;

&lt;p&gt;Imagine your Observable is a delivery service. &lt;code&gt;catchError&lt;/code&gt; is the insurance company — yes, it can’t return a lost&lt;br&gt;
package, but it will try to offer a replacement (would a monetary refund work for you?).&lt;/p&gt;

&lt;h4&gt;
  
  
  Practice
&lt;/h4&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;catchError&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;rxjs/operators&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;of&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;rxjs&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;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Observable&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="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;complete&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;catchError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&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="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Log the issue&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt; &lt;span class="c1"&gt;// Return empty array as fallback&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;orders&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="nx"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Always get data to display&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;In all examples, I'll use custom &lt;code&gt;Observable&lt;/code&gt; like this. Let’s agree that in real projects you’d use something like&lt;br&gt;
&lt;code&gt;this.http.get('/api/orders')&lt;/code&gt;. This format allows you to copy-paste code for experiments, while HTTP examples would&lt;br&gt;
require rewriting. Similarly, I use &lt;code&gt;console.log(error)&lt;/code&gt; instead of &lt;code&gt;this.logService.report(error)&lt;/code&gt; for simplicity.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;retry: Smart Retry with Control&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Philosophy
&lt;/h4&gt;

&lt;p&gt;Like a good barista remakes coffee after a mistake — &lt;code&gt;retry&lt;/code&gt; repeats requests. But remember: not all operations are&lt;br&gt;
idempotent!&lt;/p&gt;

&lt;h4&gt;
  
  
  Configuration Example
&lt;/h4&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;retry&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;timer&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;rxjs&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;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Observable&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="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;complete&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;retry&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Max 3 attempts&lt;/span&gt;
        &lt;span class="na"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;retryCount&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;timer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;retryCount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Growing delay: 1s, 2s, 3s&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Safety Rules
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Never use for POST/PUT requests&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Always set a reasonable attempt limit&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Combine with delays to protect the server&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;finalize: Guaranteed Cleanup&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Why It Matters
&lt;/h4&gt;

&lt;p&gt;No matter the battle, cleanup must happen. &lt;code&gt;finalize&lt;/code&gt; executes regardless of outcome:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Success&lt;/li&gt;
&lt;li&gt;Error&lt;/li&gt;
&lt;li&gt;Manual unsubscription&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Ideal Use Case
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&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;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Observable&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="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;complete&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;finalize&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt; &lt;span class="o"&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;// Always reset the flag&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DataLoadCompleted&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="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  &lt;strong&gt;Why We No Longer Use retryWhen?&lt;/strong&gt;
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Deprecated Approach&lt;/strong&gt;
&lt;code&gt;retryWhen&lt;/code&gt; is marked deprecated in RxJS 7.8+.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;New Capabilities&lt;/strong&gt;
The &lt;code&gt;retry&lt;/code&gt; config object is simpler and safer:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;retry&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&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;timer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Exponential backoff&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Code Readability&lt;/strong&gt;
Config objects make retry logic explicit.&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Battle-Hardened Tips&lt;/strong&gt;
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Three-Layer Rule&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Layer 1: Request retry (&lt;code&gt;retry&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Layer 2: Fallback data (&lt;code&gt;catchError&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Layer 3: Global error handler&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;80/20 Rule&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Handle 80% of errors via &lt;code&gt;catchError&lt;/code&gt;, 20% via complex strategies.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Logging as a Diary&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Always record:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Error type&lt;/li&gt;
&lt;li&gt;Operation context&lt;/li&gt;
&lt;li&gt;Timestamp&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Test Failure Scenarios&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Add 1-2 error tests for every ten positive tests.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Code without error handling is like a house with no fire exit: works until disaster strikes."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Operator Use Cases: From Theory to Practice
&lt;/h2&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Scenario 1: Graceful Data Degradation&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Problem
&lt;/h4&gt;

&lt;p&gt;The app crashes if the API returns 404 on a product page.&lt;/p&gt;

&lt;h4&gt;
  
  
  Solution with &lt;code&gt;catchError&lt;/code&gt;
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;product$&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;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/api/products/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&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="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;catchError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&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="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Product temporarily unavailable&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/assets/placeholder.jpg&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="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Propagate other errors&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;&lt;strong&gt;Effect:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Users see an informative card instead of a blank screen.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Scenario 2: Smart Request Retries&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Problem
&lt;/h4&gt;

&lt;p&gt;Mobile clients often lose connection while loading news feeds.&lt;/p&gt;

&lt;h4&gt;
  
  
  Solution with &lt;code&gt;retry&lt;/code&gt;
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/feed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;retry&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Max 3 attempts&lt;/span&gt;
        &lt;span class="na"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;retryCount&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;timer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;retryCount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Linear delay&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="nf"&gt;catchError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&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="nx"&gt;offlineService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;showWarning&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;EMPTY&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="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Stats:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Reduced feed loading errors in unstable network conditions.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Scenario 3: Complex Payment Processing&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Problem
&lt;/h4&gt;

&lt;p&gt;Need to guarantee payment clearing even during errors.&lt;/p&gt;

&lt;h4&gt;
  
  
  Operator Combination
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;processPayment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;paymentData&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;retry&lt;/span&gt;&lt;span class="p"&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;// Retry for temporary failures&lt;/span&gt;
    &lt;span class="nf"&gt;catchError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&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="nx"&gt;fallbackProcessor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;paymentData&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;EMPTY&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="nf"&gt;finalize&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cleanupResources&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="nx"&gt;logService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;flush&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Guaranteed log write&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Architecture Tip:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Always separate "retryable" and "fatal" errors.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Scenario 4: Background Sync&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Problem
&lt;/h4&gt;

&lt;p&gt;Background sync process "hangs" on errors.&lt;/p&gt;

&lt;h4&gt;
  
  
  Solution with &lt;code&gt;finalize&lt;/code&gt;
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;syncJob&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="nx"&gt;_000&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;switchMap&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;syncService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
    &lt;span class="nf"&gt;finalize&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;jobRegistry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unregister&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;background-sync&lt;/span&gt;&lt;span class="dl"&gt;'&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="nx"&gt;memoryCache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clear&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="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key Point:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Resources are released even with manual unsubscription.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Battlefield Tips&lt;/strong&gt;
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;"Layered Defense" Pattern&lt;/strong&gt;
Combine operators as filters:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Stream → retry(3) → catchError → finalize
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Metrics Are Your Friends&lt;/strong&gt;
Add error counters:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;catchError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&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="nx"&gt;metrics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;API_ERRORS&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;error&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;ol&gt;
&lt;li&gt;
&lt;strong&gt;Test Edge Cases&lt;/strong&gt;
Use marble diagrams to simulate errors:&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Error Handling Strategies: How to Avoid Drowning in Exceptions&lt;/strong&gt;
&lt;/h3&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;1. "Safe Islands" Strategy&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Concept
&lt;/h4&gt;

&lt;p&gt;Break the stream into independent segments with local error handling. Like watertight compartments in a ship.&lt;/p&gt;

&lt;h4&gt;
  
  
  Implementation
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;merge&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;loadUserData&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nf"&gt;catchError&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;// Errors won't break other streams&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;loadProducts&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nf"&gt;retry&lt;/span&gt;&lt;span class="p"&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;// Custom retry policy&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;finalize&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;hideLoader&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="c1"&gt;// Shared cleanup point&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Effect:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Errors in one stream don’t crash the entire system.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;2. "Layered Defense" Strategy&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Three-Tier Model
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Request Level:&lt;/strong&gt;
Retries for temporary failures
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(...).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;retry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Component Level:&lt;/strong&gt;
Fallback data
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;catchError&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getData&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Application Level:&lt;/strong&gt;
Global error interceptor
&lt;/li&gt;
&lt;/ol&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;Injectable&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;GlobalErrorHandler&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;ErrorHandler&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;handleError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&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="nx"&gt;sentry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;captureException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&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;h3&gt;
  
  
  &lt;strong&gt;3. "Smart Retry" Strategy&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  When to Use
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Services with unstable connections&lt;/li&gt;
&lt;li&gt;Mission-critical operations&lt;/li&gt;
&lt;li&gt;Background syncs&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Exponential Backoff Pattern
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;retry&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;retryCount&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;timer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="nx"&gt;retryCount&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;&lt;strong&gt;Real-World Stats:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Successful recovery in most cases with 4 attempts.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;4. "Silent Fail" Strategy&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Purpose
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Non-data-critical components&lt;/li&gt;
&lt;li&gt;Demo modes&lt;/li&gt;
&lt;li&gt;Functional degradation scenarios (e.g., switching from streams to HTTP requests)&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Implementation
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;liveUpdates$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;websocketStream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;catchError&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;interval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nf"&gt;switchMap&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/polling-endpoint&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="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;&lt;strong&gt;Effect:&lt;/strong&gt;&lt;br&gt;
Users continue working in a limited mode.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;5. "Explicit Failure" Strategy&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  When to Use
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Financial operations&lt;/li&gt;
&lt;li&gt;Legally binding actions&lt;/li&gt;
&lt;li&gt;Security systems&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Implementation
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;processTransaction&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;tap&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;error&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rollbackTransaction&lt;/span&gt;&lt;span class="p"&gt;()}),&lt;/span&gt;
    &lt;span class="nf"&gt;catchError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&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;showFatalError&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;error&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;&lt;strong&gt;Golden Rule:&lt;/strong&gt;&lt;br&gt;
Better to fail explicitly than enter an invalid state.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Strategy Selection Checklist&lt;/strong&gt;
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;How critical is the operation?&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Money/security → "Explicit Failure"&lt;/li&gt;
&lt;li&gt;Data viewing → "Silent Fail"&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;How frequent are errors?&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Often → "Layered Defense"&lt;/li&gt;
&lt;li&gt;Rare → "Safe Islands"&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;What resources are available?&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Cache exists → "Smart Retry"&lt;/li&gt;
&lt;li&gt;No fallbacks → "Silent Fail"&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Strategy without metrics is like a compass without a needle."&lt;br&gt;&lt;br&gt;
— Observability Principle in Microservices&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Common Beginner Mistakes: How to Avoid Pitfalls
&lt;/h2&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;1. Silent Error Swallowing&lt;/strong&gt;
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ❌ Problematic Approach
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&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;// Errors? What errors?&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;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&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;&lt;strong&gt;Consequences:&lt;/strong&gt;&lt;br&gt;
Users see a frozen UI, errors go unlogged.&lt;/p&gt;

&lt;h4&gt;
  
  
  ✅ Correct Solution
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;next&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;handleError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Always handle errors&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  &lt;strong&gt;2. Infinite Retry Loops&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  ❌ Dangerous Code
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/orders&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;retry&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// Infinite loop on 500 errors&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Risks:&lt;/strong&gt;&lt;br&gt;
Self-inflicted DDoS, mobile battery drain.&lt;/p&gt;

&lt;h4&gt;
  
  
  ✅ Safe Approach
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;retry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Clear attempt limit&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  &lt;strong&gt;3. Ignoring Unsubscriptions&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  ❌ Common Pitfall
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;ngOnInit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&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;// Subscription lives forever after route changes&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;updateRealTimeData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&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;&lt;strong&gt;Effect:&lt;/strong&gt;&lt;br&gt;
Memory leaks, update conflicts.&lt;/p&gt;

&lt;h4&gt;
  
  
  ✅ Professional Approach
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt;
&lt;span class="nx"&gt;destroy$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Subject&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nf"&gt;ngOnInit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nf"&gt;takeUntil&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="nx"&gt;destroy$&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(...);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;ngOnDestroy&lt;/span&gt;&lt;span class="p"&gt;()&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="nx"&gt;destroy$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&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="nx"&gt;destroy$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;complete&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;h3&gt;
  
  
  &lt;strong&gt;4. Global Handler as a "Trash Can"&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  ❌ Anti-Pattern
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// global-error-handler.ts&lt;/span&gt;
&lt;span class="nf"&gt;handleError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="c1"&gt;// Catch ALL errors indiscriminately&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;sentry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;captureException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&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;&lt;strong&gt;Issue:&lt;/strong&gt;&lt;br&gt;
No way to customize handling for specific scenarios.&lt;/p&gt;

&lt;h4&gt;
  
  
  ✅ Stratified Approach
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Local handling&lt;/span&gt;
&lt;span class="nf"&gt;catchError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;handleLocalError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="c1"&gt;// Global handler&lt;/span&gt;
&lt;span class="nf"&gt;handleError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isCritical&lt;/span&gt;&lt;span class="p"&gt;)&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="nx"&gt;sentry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;captureException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&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;h3&gt;
  
  
  &lt;strong&gt;Self-Check Checklist&lt;/strong&gt;
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Do all subscriptions have &lt;code&gt;error&lt;/code&gt; handling?&lt;/li&gt;
&lt;li&gt;Are there &lt;code&gt;retry&lt;/code&gt; attempt limits?&lt;/li&gt;
&lt;li&gt;Is &lt;code&gt;takeUntil&lt;/code&gt; used for unsubscriptions?&lt;/li&gt;
&lt;li&gt;Are global and local errors separated?&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Errors are like rakes: to stop stepping on them, you must first see them in the code."&lt;br&gt;&lt;br&gt;
— Another "auf" principle from dev memes&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Conclusion: Errors as a Path to Mastery
&lt;/h1&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;What Have We Learned?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Through years of working with RxJS, I've realized: &lt;strong&gt;true mastery begins where others see problems&lt;/strong&gt;. Error handling&lt;br&gt;
isn’t routine—it’s the art of designing resilient systems.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Lessons:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Error Handling is a Code Maturity Indicator&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Every &lt;code&gt;catchError&lt;/code&gt; in your code is a step toward professional-grade development.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Retries ≠ Panacea&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Properly configured &lt;code&gt;retry&lt;/code&gt; saves where naive implementations harm.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"The best error is the one that never happens. The second best—the one handled gracefully."&lt;br&gt;&lt;br&gt;
— Ancient Developer Proverb&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Where to Go Next?&lt;/strong&gt;
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Experiment with Combinations&lt;/strong&gt;
Example of an advanced chain:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;   &lt;span class="nx"&gt;data$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
   &lt;span class="nf"&gt;retryWhen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;exponentialBackoff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
   &lt;span class="nf"&gt;catchError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;switchToCache&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
   &lt;span class="nf"&gt;finalize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cleanup&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;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Study Real-World Cases&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Explore source code of Angular HttpClient and Ngrx — treasure troves of patterns.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Share Knowledge&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Write a post about your toughest error — the best way to solidify experience.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"In 20 years of development, I’ve seen many 'perfect' systems. They all broke. The ones that survived treated errors&lt;br&gt;
as part of the design."&lt;br&gt;&lt;br&gt;
— Someone, definitely, once said to someone*&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;&lt;strong&gt;Your Next Step:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Open your latest project. Find at least one stream without error handling — and turn it into a reliability example.&lt;br&gt;&lt;br&gt;
Remember: every handled failure saves hours of support and thousands of satisfied users. &lt;/p&gt;

</description>
      <category>rxjs</category>
    </item>
    <item>
      <title>The Fourth Step into the World of RxJS: Unfinished Streams - Silent Killers of Applications</title>
      <dc:creator>Art Stesh</dc:creator>
      <pubDate>Sat, 17 May 2025 14:00:00 +0000</pubDate>
      <link>https://dev.to/artstesh/the-fourth-step-into-the-world-of-rxjs-unfinished-streams-silent-killers-of-applications-2njb</link>
      <guid>https://dev.to/artstesh/the-fourth-step-into-the-world-of-rxjs-unfinished-streams-silent-killers-of-applications-2njb</guid>
      <description>&lt;p&gt;Throughout the first, second, and third articles, we have embarked on a fascinating journey together: from our initial introduction to Observables, where we grasped the fundamentals of the reactive approach, through mastering operators that enabled us to efficiently transform and filter data, to combining streams, which unlocked the ability to synchronize data from multiple sources. We gradually transformed RxJS from an intriguing tool for experimentation into a powerful instrument for real-world tasks.&lt;/p&gt;

&lt;p&gt;Now, having taken three confident steps, it is time to confront the dark side of reactive programming. Like any technology, RxJS has its pitfalls. One of the most insidious is unclosed subscriptions, which can lead to severe issues such as memory leaks, performance degradation, and even application crashes. The true power of RxJS tools demands not only technical knowledge from developers but also genuine professional expertise to build reliable and high-performance applications.&lt;/p&gt;

&lt;p&gt;If the first three steps were about creating and transforming streams, the fourth step is about taking responsibility for what has been created. This is a stride toward maturity in working with RxJS—understanding why subscription management is critical and how it impacts the quality of your applications.&lt;/p&gt;

&lt;p&gt;Join us to delve deeper into the world of RxJS, avoid common pitfalls, and become a developer who not only crafts engaging code but also ensures it is robust, optimized, and adaptable to any operational environment.&lt;/p&gt;

&lt;h3&gt;
  
  
  Threats When Working with RxJS
&lt;/h3&gt;

&lt;p&gt;Modern Angular is hard to imagine today without RxJS. It empowers us to handle asynchronous tasks, manage state reactively, respond to events, and even construct complex data processing pipelines.&lt;/p&gt;

&lt;p&gt;With &lt;code&gt;RxJS&lt;/code&gt;, you work with &lt;strong&gt;data streams&lt;/strong&gt; (&lt;code&gt;Observable&lt;/code&gt;). When you subscribe to an &lt;code&gt;Observable&lt;/code&gt;, imagine it as attaching a hose to a water tap. The data stream starts flowing, events pour into your application in a continuous stream. The problem is that the tap won't close until you manually turn the handle.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Subscriptions without &lt;code&gt;unsubscribe&lt;/code&gt; are silent killers. While you test everything in short development sessions, the app works perfectly... until a QA engineer complains about smoke coming from their laptop after 30 minutes of interacting with your creation.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Imagine you created a subscription inside an Angular component but forgot to "close" it when the component is no longer needed (e.g., the user navigates to another part of the app). What happens?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Data continues to flow.&lt;/strong&gt; Even if the UI no longer uses this data, the subscription remains active. This means that even when no one is watching, the stream keeps emitting events, straining both your system and the server.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Memory stops being freed.&lt;/strong&gt; RxJS streams act as long-lived objects. As long as the subscription is active, references to data persist in memory, and the garbage collector (GC) cannot release them.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Hidden issues escalate.&lt;/strong&gt; At first, this might seem unimportant — everything works. But after a few hours of app runtime (or several component navigations), problems start compounding:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Performance degradation.&lt;/li&gt;
&lt;li&gt;Memory leaks.&lt;/li&gt;
&lt;li&gt;Browser crashes (especially on low-end devices).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;Why Won't You Notice the Problem Immediately?&lt;br&gt;
During development, it's easy to overlook RxJS subscription details. Everything looks fine: data updates correctly, no console errors, performance seems adequate in short sessions. But inefficiency always catches up.&lt;br&gt;
The first serious memory leak might strike days or weeks later when the app reaches users with low-end devices. Then you'll face an odyssey of hunting "phantom" bugs, blaming environment issues, and cursing "user error"...&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Memory Leak Example
&lt;/h3&gt;

&lt;p&gt;Imagine developing a real-time chat widget for a website. It receives live messages and displays them on the page. Everything seems perfect, but there's a hidden flaw. A tiny oversight... until the first performance degradation report lands directly from an end-user.&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;ChangeDetectionStrategy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ChangeDetectorRef&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;OnDestroy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;OnInit&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;map&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="s2"&gt;rxjs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;NgForOf&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="s2"&gt;@angular/common&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;instance&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;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-chat&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;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="nx"&gt;NgForOf&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;h2&amp;gt;Real-time Chat&amp;lt;/h2&amp;gt;
    &amp;lt;div class="chat-window"&amp;gt;
      &amp;lt;div *ngFor="let message of messages" class="message"&amp;gt;
        {{ message }}
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;`
    .chat-window {
      border: 1px solid #ccc;
      height: 300px;
      overflow-y: auto;
    }
    .message {
      padding: 8px;
      border-bottom: 1px solid #eee;
    }
  `&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;ChatComponent&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;OnInit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;OnDestroy&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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="nx"&gt;instanceId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// Creation of a random string&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;getRandomString&lt;/span&gt; &lt;span class="o"&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="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&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;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;36&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;substring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&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="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;detector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ChangeDetectorRef&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="nf"&gt;ngOnInit&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="c1"&gt;// Creation of a new data-stream every 0.5 sec&lt;/span&gt;
        &lt;span class="nf"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;i&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;`New message #&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;i&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;span class="s2"&gt; - &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;fill&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="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;getRandomString&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&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;// Симуляция тяжелых данных&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&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;// Adding of the message to the collection&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;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&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="nx"&gt;detector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;detectChanges&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;`The subscription &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="nx"&gt;instanceId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; is finished.`&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="nf"&gt;ngOnDestroy&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&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;`ChatComponent &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="nx"&gt;instanceId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; destroyed`&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;h4&gt;
  
  
  What's Wrong with This Component?
&lt;/h4&gt;

&lt;p&gt;At first glance, nothing catastrophic: UI updates, everything works as intended.&lt;/p&gt;

&lt;p&gt;But here's the catch: &lt;strong&gt;You did NOT unsubscribe from the stream!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When the user hides the chat, the &lt;code&gt;ChatComponent&lt;/code&gt; gets destroyed. But the subscription firing twice per second continues to "live". It keeps generating messages to send... nowhere. As a result:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The stream &lt;strong&gt;remains active&lt;/strong&gt;. Messages keep being generated in memory.&lt;/li&gt;
&lt;li&gt;References to the &lt;code&gt;messages[]&lt;/code&gt; array persist in memory.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;Garbage Collector&lt;/strong&gt; (&lt;code&gt;GC&lt;/code&gt;) cannot free allocated resources because the subscription maintains a "live" reference.&lt;/li&gt;
&lt;/ul&gt;




&lt;h4&gt;
  
  
  Let's See This in Action:
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Download the project &lt;a href="https://github.com/artstesh/article-examples/tree/master/Unsubscribe" rel="noopener noreferrer"&gt;from here&lt;/a&gt; and run it.&lt;/li&gt;
&lt;li&gt;Open browser DevTools and navigate to the &lt;strong&gt;Console&lt;/strong&gt; tab.&lt;/li&gt;
&lt;li&gt;Click the chat open/close button multiple times.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You'll see an ever-increasing number of console messages. Worst of all, messages from &lt;strong&gt;already destroyed chat instances&lt;/strong&gt; will keep appearing. In the &lt;strong&gt;Memory&lt;/strong&gt; tab, you'll observe endless growth of application resource usage.&lt;/p&gt;




&lt;h3&gt;
  
  
  Why Is This Bad? Memory Leaks and Their Impact
&lt;/h3&gt;

&lt;p&gt;When you subscribe to an Observable stream, it creates a reference to your subscriber code. An RxJS stream remains "alive" as long as there's at least one active subscription. This means that if you don't unsubscribe, the associated data will linger in memory indefinitely.&lt;/p&gt;

&lt;p&gt;In our example, the subscription maintains a reference to the &lt;code&gt;messages[]&lt;/code&gt; array. Even if the user closes the chat:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;New &lt;code&gt;message&lt;/code&gt; objects keep being generated and added to the array, though no longer needed.&lt;/li&gt;
&lt;li&gt;Old array references stay "alive", and the Garbage Collector (&lt;code&gt;GC&lt;/code&gt;) cannot reclaim them because the stream remains
active.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The result? Memory gradually &lt;strong&gt;clogs up&lt;/strong&gt;. In early stages, this goes unnoticed, but after 5-10 minutes of runtime, the app suddenly starts lagging.&lt;/p&gt;

&lt;p&gt;The more active subscriptions remain, the more data your RxJS stream processes. Consequences:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;CPU load spikes&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Low-end devices&lt;/strong&gt; (e.g., older phones) struggle with excess computations.&lt;/li&gt;
&lt;li&gt;At the worst possible moment, the browser &lt;strong&gt;crashes&lt;/strong&gt; or severe GUI delays occur.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In our chat example, the bug is particularly dangerous because new messages are generated every 500ms. Multiply this by the number of abandoned subscriptions — and you get a disaster.&lt;/p&gt;




&lt;h3&gt;
  
  
  Why Isn't This Obvious?
&lt;/h3&gt;

&lt;p&gt;Memory leak-related errors often develop gradually. Here are reasons why developers neglect &lt;code&gt;unsubscribe&lt;/code&gt; early in development:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Initial performance seems fine.&lt;/strong&gt; At first, you notice nothing — subscriptions work, UI updates.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Diagnostic complexity.&lt;/strong&gt; Memory leaks only manifest long-term. You rarely "see" anomalies during short testing sessions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Angular handles many tasks automatically.&lt;/strong&gt; Framework tools often "mask" the issue until it accumulates.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Optimistic mindset.&lt;/strong&gt; "It works — must be okay". But the truth is: unclosed subscriptions &lt;strong&gt;will&lt;/strong&gt; cause issues at the worst possible time.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  How to Fix It? Closing Subscriptions
&lt;/h3&gt;

&lt;p&gt;Now that we understand leaving subscriptions open is bad, let's explore reliable solutions. Proper subscription management in Angular isn't as hard as it seems — make it a rule from day one.&lt;/p&gt;

&lt;h4&gt;
  
  
  1. &lt;strong&gt;Use &lt;code&gt;Subscription&lt;/code&gt; for Manual Management&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;RxJS provides the &lt;code&gt;Subscription&lt;/code&gt; class to manage subscriptions. By explicitly storing subscriptions, you can unsubscribe when the component is destroyed. Let's modify our problematic code using &lt;code&gt;Subscription&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="k"&gt;import&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;ChangeDetectorRef&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;OnDestroy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;OnInit&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Subscription&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="s2"&gt;rxjs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;NgForOf&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="s2"&gt;@angular/common&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;instance&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;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-chat&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;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="nx"&gt;NgForOf&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;h2&amp;gt;Real-time Chat&amp;lt;/h2&amp;gt;
    &amp;lt;div class="chat-window"&amp;gt;
      &amp;lt;div *ngFor="let message of messages" class="message"&amp;gt;
        {{ message }}
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;`
    .chat-window {
      border: 1px solid #ccc;
      height: 300px;
      overflow-y: auto;
    }
    .message {
      padding: 8px;
      border-bottom: 1px solid #eee;
    }
  `&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;ChatComponent&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;OnInit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;OnDestroy&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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="nx"&gt;instanceId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;subscriptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Subscription&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="c1"&gt;// Store all subscriptions here&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;getRandomString&lt;/span&gt; &lt;span class="o"&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="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&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;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;36&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;substring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&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="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;detector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ChangeDetectorRef&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="nf"&gt;ngOnInit&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Add observable to subscriptions list&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;subscriptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;i&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;`New message #&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;i&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;span class="s2"&gt; - &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fill&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="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;getRandomString&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&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="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&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;// Add new message to the list&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;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&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="nx"&gt;detector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;detectChanges&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;`Subscription &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="nx"&gt;instanceId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; executed.`&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="nf"&gt;ngOnDestroy&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Unsubscribe from all observables&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;subscriptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unsubscribe&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;`ChatComponent &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="nx"&gt;instanceId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; destroyed`&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;&lt;strong&gt;What's Happening Here?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We create a &lt;code&gt;Subscription&lt;/code&gt; object to store our message stream.&lt;/li&gt;
&lt;li&gt;When the component is destroyed (&lt;code&gt;ngOnDestroy&lt;/code&gt;), we call &lt;code&gt;.unsubscribe()&lt;/code&gt;, terminating the data stream observation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the simplest and most straightforward approach. By storing subscriptions separately, you retain full manual control.&lt;/p&gt;

&lt;p&gt;You can also create a utility class to encapsulate this logic:&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;OnDestroy&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;Subscription&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;rxjs&lt;/span&gt;&lt;span class="dl"&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;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DestructibleComponent&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;OnDestroy&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nx"&gt;subs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Subscription&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="k"&gt;protected&lt;/span&gt; &lt;span class="nx"&gt;onDestroy&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="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nf"&gt;ngOnDestroy&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&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="nx"&gt;subs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unsubscribe&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
        &lt;span class="k"&gt;if &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="nx"&gt;onDestroy&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;onDestroy&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;Any component can inherit this class (&lt;code&gt;extends&lt;/code&gt;) and add subscriptions to the &lt;code&gt;subs&lt;/code&gt; array without redefining &lt;code&gt;ngOnDestroy&lt;/code&gt;. For additional cleanup logic, the &lt;code&gt;onDestroy&lt;/code&gt; method is available — it runs after unsubscriptions without interfering with them.&lt;/p&gt;




&lt;h4&gt;
  
  
  2. &lt;strong&gt;Use AsyncPipe: Minimal Code&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;If your data is only displayed in templates (e.g., via &lt;code&gt;*ngFor&lt;/code&gt; or &lt;code&gt;{{ }}&lt;/code&gt;), you can avoid manual subscriptions in TypeScript altogether. Angular's &lt;code&gt;AsyncPipe&lt;/code&gt; handles unsubscriptions automatically.&lt;/p&gt;

&lt;p&gt;Here's an example:&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;ChangeDetectionStrategy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ChangeDetectorRef&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;OnDestroy&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;tap&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="s2"&gt;rxjs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;AsyncPipe&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;NgForOf&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="s2"&gt;@angular/common&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;instance&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;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-chat&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;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="nx"&gt;NgForOf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;AsyncPipe&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;h2&amp;gt;Real-time Chat&amp;lt;/h2&amp;gt;
    &amp;lt;div class="chat-window"&amp;gt;
      &amp;lt;div *ngFor="let message of messages$ | async" class="message"&amp;gt;
        {{ message }}
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;`
    .chat-window {
      border: 1px solid #ccc;
      height: 300px;
      overflow-y: auto;
    }
    .message {
      padding: 8px;
      border-bottom: 1px solid #eee;
    }
  `&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;ChatComponent&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;OnDestroy&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;instanceId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;getRandomString&lt;/span&gt; &lt;span class="o"&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="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&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;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;36&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;substring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;messages$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nf"&gt;tap&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;`Subscription &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="nx"&gt;instanceId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; is done.`&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
            &lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;idx&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;`New message #&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;idx&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;span class="s2"&gt; - &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;fill&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="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;getRandomString&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&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="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="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;detector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ChangeDetectorRef&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="nf"&gt;ngOnDestroy&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&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;`ChatComponent &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="nx"&gt;instanceId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; destroyed`&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;&lt;strong&gt;Why is &lt;code&gt;AsyncPipe&lt;/code&gt; Awesome?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Automatically subscribes to Observables when the template renders.&lt;/li&gt;
&lt;li&gt;Unsubscribes automatically when the component is destroyed.&lt;/li&gt;
&lt;li&gt;Keeps code extremely concise.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;When to Use It?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Use &lt;code&gt;AsyncPipe&lt;/code&gt; if the data stream is &lt;strong&gt;only&lt;/strong&gt; consumed in the template and nowhere else in the code.&lt;/p&gt;




&lt;h3&gt;
  
  
  Best Practices for Subscription Management
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. &lt;strong&gt;Adopt a Unified Approach&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Stick to one subscription management style across your project. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Inherit &lt;code&gt;DestructibleComponent&lt;/code&gt; for all components.&lt;/li&gt;
&lt;li&gt;Use the widely-known &lt;code&gt;takeUntil&lt;/code&gt; pattern.&lt;/li&gt;
&lt;li&gt;Use manual &lt;code&gt;Subscription&lt;/code&gt; management for niche cases.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  2. &lt;strong&gt;Minimize Subscriptions&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Combine streams using operators like &lt;code&gt;merge&lt;/code&gt;, &lt;code&gt;combineLatest&lt;/code&gt;, or &lt;code&gt;switchMap&lt;/code&gt; instead of creating multiple small subscriptions.&lt;/p&gt;

&lt;h4&gt;
  
  
  3. &lt;strong&gt;Prefer &lt;code&gt;AsyncPipe&lt;/code&gt;&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Whenever possible, use &lt;code&gt;AsyncPipe&lt;/code&gt; for template-bound data.&lt;/p&gt;

&lt;h4&gt;
  
  
  4. &lt;strong&gt;Monitor Performance in DevTools&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Regularly audit app performance:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use the &lt;strong&gt;Memory&lt;/strong&gt; tab to detect leaks.&lt;/li&gt;
&lt;li&gt;Profile with &lt;strong&gt;Performance&lt;/strong&gt; to spot anomalies.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  5. &lt;strong&gt;Log Subscription Cleanup During Development&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Add &lt;code&gt;console.log&lt;/code&gt; in &lt;code&gt;ngOnDestroy&lt;/code&gt; to verify subscriptions close on component destruction.&lt;/p&gt;




&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Working with RxJS isn't just about mastering a new tool — it's a journey toward more efficient, organized, and profound modern app development. Along this path, mistakes like unclosed subscriptions are inevitable, but each is a step forward in your professional growth.&lt;/p&gt;

&lt;p&gt;RxJS, like any complex yet powerful skill, demands patience, practice, and relentless determination to improve.&lt;/p&gt;

&lt;p&gt;Keep experimenting, learning, and diving into details. Remind yourself that every hour spent mastering fundamentals pays off exponentially: in development speed, app stability, and the respect of colleagues who'll see you as a true professional.&lt;/p&gt;

&lt;p&gt;The browser's memory, your users, and your team will thank you. Experiment boldly, make mistakes, fix them, learn, and push toward new horizons. Success in every aspect of development stems from your own effort to transform today's challenges into tomorrow's expertise.&lt;/p&gt;

</description>
      <category>rxjs</category>
    </item>
    <item>
      <title>Frontend as the New Legacy: How We Missed the Event-Driven Paradigm Shift</title>
      <dc:creator>Art Stesh</dc:creator>
      <pubDate>Sat, 10 May 2025 11:41:56 +0000</pubDate>
      <link>https://dev.to/artstesh/frontend-as-the-new-legacy-how-we-missed-the-event-driven-paradigm-shift-188d</link>
      <guid>https://dev.to/artstesh/frontend-as-the-new-legacy-how-we-missed-the-event-driven-paradigm-shift-188d</guid>
      <description>&lt;h3&gt;
  
  
  Introduction: Architectural Déjà Vu
&lt;/h3&gt;

&lt;p&gt;Have you ever noticed how the digital world moves in spirals? In 2018, I was waving around Dockerfile and Helm charts, implementing microservices in C# with RabbitMQ — all for the sacred goal of &lt;strong&gt;low coupling&lt;/strong&gt;. Three years later, having switched to Angular, I was horrified to realize: frontend components were communicating through Input/Output chains, as if it were 2005 and we were writing WinForms.&lt;/p&gt;

&lt;p&gt;It's like assembling a spaceship but controlling it via telegraph. In the backend, we proudly declare &lt;strong&gt;event-driven architecture&lt;/strong&gt;, while on the frontend, components whisper through props like teenagers at a school dance. The irony? The more complex our systems became, the more they resembled the very monoliths we fled from in the backend world.&lt;/p&gt;

&lt;p&gt;My epiphany came when I had to modify a dialog box. To add a "Cancel" button, I needed to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Update the parent component&lt;/li&gt;
&lt;li&gt;Rewrite the mediator service&lt;/li&gt;
&lt;li&gt;Fix three child modules&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Twelve files for one button!&lt;/strong&gt; In the microservices world, this would be like editing five repositories to change a label color. I asked myself: &lt;em&gt;"Why hasn’t the frontend learned from distributed systems?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;We’ve mastered WebAssembly, adopted GraphQL, modularized CSS — yet component communication remains stuck in the jQuery era. As if architects forgot that React, Angular, and Vue aren’t just about rendering, but &lt;strong&gt;interaction between independent agents&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;But what if I told you the solution has existed for decades? That the pattern powering RabbitMQ, Kafka, and AWS SQS could save the frontend? That it requires no heavy libraries — just 15 KB of code and a paradigm shift in how we view components.&lt;/p&gt;

&lt;p&gt;Let’s dive into the rabbit hole of event-driven design. After this article, your components might stop whispering and start conversing like mature, independent modules.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 1: Historical Context — 40 Years of Pub/Sub Evolution
&lt;/h2&gt;

&lt;p&gt;In 1983, when programmers manually set motherboard jumpers, Xerox PARC’s Adele Goldberg was coding Smalltalk-80. Her lab birthed an idea that would outlive PCs, the web, and mobile: &lt;em&gt;"Objects should communicate through messages, not method calls."&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Evolution Across Three Eras
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1. Tribal Era (1980–2000)&lt;/strong&gt;&lt;br&gt;
Smalltalk objects exchanged messages like primitive tribes — directly, without intermediaries. The problem? To send a " message," you needed to know the exact location of the recipient "tribe."&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight smalltalk"&gt;&lt;code&gt;&lt;span class="c"&gt;"Tribe A sends a message to Tribe B"&lt;/span&gt;
&lt;span class="nc"&gt;B&lt;/span&gt; &lt;span class="nf"&gt;primitive:&lt;/span&gt; &lt;span class="s"&gt;'The fire is out!'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Imperial Era (2000–2010)&lt;/strong&gt;&lt;br&gt;
CORBA and Enterprise Service Bus (ESB) turned messaging into bureaucracy. You had to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Know WSDL contracts&lt;/li&gt;
&lt;li&gt;Register endpoints&lt;/li&gt;
&lt;li&gt;Build XML schemas&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On a 2010 project, we spent three weeks integrating SAP with .NET via ESB. When we asked the architect, "Why not simplify it?" he replied, "This is enterprise — that’s how it’s done here."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Globalization Era (2010–Present)&lt;/strong&gt;&lt;br&gt;
Kafka, RabbitMQ, and cloud queues turned Pub/Sub into the &lt;em&gt;lingua franca&lt;/em&gt; of microservices. The rules simplified:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Message format = the only contract&lt;/li&gt;
&lt;li&gt;Publishers don’t know subscribers&lt;/li&gt;
&lt;li&gt;Brokers guarantee delivery&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Philosophical Shift: From Commands to Contracts
&lt;/h3&gt;

&lt;p&gt;Pub/Sub is a digital incarnation of &lt;em&gt;Rousseau’s social contract&lt;/em&gt;. When a module publishes a &lt;code&gt;PriceChangedEvent&lt;/code&gt;, it essentially declares:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"I don’t know who needs this"&lt;/li&gt;
&lt;li&gt;"But if you want it — listen"&lt;/li&gt;
&lt;li&gt;"I promise the format: {itemId: string, newPrice: number}"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This mirrors TCP/IP for humans: just as data packets don’t care if you’re a browser or email client, messages don’t care if you’re Angular or React.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;Why Has Pub/Sub Survived 40 Years of Tech Revolutions?&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Antifragility&lt;/strong&gt;: Systems learn to live with errors (recall the Dead Letter Queues principle)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Language Agnosticism&lt;/strong&gt;: Messages don’t care what you code in — they’re like Esperanto for microservices&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Evolutionary Design&lt;/strong&gt;: You can start with a simple bus and scale to distributed streaming&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Once at a meetup, I heard: "Kafka is Smalltalk for big data." There might be some truth — both approaches teach systems to communicate politely without unnecessary questions.&lt;/p&gt;

&lt;p&gt;In the next part, we’ll take this 40-year experience and apply it to Angular components — making them stop poking each other via Input/Output and start speaking the language of independent messages.&lt;/p&gt;


&lt;h3&gt;
  
  
  Frontend: Stuck in the Past?
&lt;/h3&gt;

&lt;p&gt;While backend migrated from SOAP to events in the 2010s, frontend was busy inventing… &lt;code&gt;@Output()&lt;/code&gt;. Angular components are stuck with relics of the imperial era:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Rigid call hierarchies&lt;/li&gt;
&lt;li&gt;Services as ESB-like monsters&lt;/li&gt;
&lt;li&gt;Events passing through 5 layers — like bureaucratic mail&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once, to add analytics for a button in a child component, we had to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add &lt;code&gt;@Output() analyticsEvent&lt;/code&gt; to component D&lt;/li&gt;
&lt;li&gt;Pass it through B → C → A&lt;/li&gt;
&lt;li&gt;Subscribe in the root component&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A ton of work for a single line: &lt;code&gt;analytics.track('click')&lt;/code&gt;. It’s like delivering a letter to your neighbor via three post offices.&lt;/p&gt;
&lt;h3&gt;
  
  
  Lessons the Frontend Missed
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1. Events ≠ Call Chains&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Backend figured out long ago: if microservice A calls B, and B calls C — that’s an anti-pattern. But in frontend, @Output() → service → @Input() is considered normal.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Broker ≠ Single Point of Failure&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;RabbitMQ handles millions of messages. A typical Angular service with Subjects crashes at 1000 events per second.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Format &amp;gt; Implementation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Backend uses OpenAPI/Swagger to define contracts. Frontend still works with &lt;code&gt;any&lt;/code&gt; in events.&lt;/p&gt;


&lt;h3&gt;
  
  
  Dawn of Hope: Web Components
&lt;/h3&gt;

&lt;p&gt;Ironically, the future of event-driven frontend began in 2011 with the concept of Web Components. Their &lt;code&gt;Custom Events&lt;/code&gt; align closer to Pub/Sub philosophy than the Angular approach:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Component A&lt;/span&gt;
&lt;span class="nf"&gt;dispatchEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CustomEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;price-changed&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;detail&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;itemId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;45&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}));&lt;/span&gt;

&lt;span class="c1"&gt;// Component B&lt;/span&gt;
&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;price-changed&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="nx"&gt;e&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="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;price&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;This echoes early Smalltalk principles but with HTML5 syntax. It's a pity frameworks didn't pursue this path further.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Historical Paradox&lt;/strong&gt;: Frontend technologies refresh every 2 years, yet architectural patterns remain stuck in the 2000s. Perhaps it's time to stop reinventing wheels and borrow solutions from... 40-year-old Smalltalk.&lt;/p&gt;

&lt;p&gt;In the next part, we'll explore how these principles apply to modern Angular applications – and why &lt;code&gt;@Input/@Output&lt;/code&gt; can be more dangerous than they appear. Spoiler: it's like building a castle wall that's harder to scale from the inside than outside.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 2: Frontend Dilemma – When Components Start Gossiping
&lt;/h2&gt;

&lt;p&gt;You know that moment when you open a colleague's code and see a component that knows too much? Like that neighbor who monitors everyone through security cameras. In the Angular world, this often starts with innocent &lt;code&gt;@Input()&lt;/code&gt; and &lt;code&gt;@Output()&lt;/code&gt;, but quickly evolves into a dependency web. Let's uncover why traditional approaches sometimes resemble a game of "broken telephone".&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Problem 1: Input/Output as Chain Reactions&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Imagine a &lt;code&gt;ProductCard&lt;/code&gt; component that should show a modal on click. The classic approach:&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="c1"&gt;// product-card.component.ts&lt;/span&gt;
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Output&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nx"&gt;openModal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;EventEmitter&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="nf"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;()&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="nx"&gt;openModal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;product-details&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="c1"&gt;// parent.component.html&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nf"&gt;card&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;openModal&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;handleModal($event)&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/product-card&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;modal&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;modalType&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/modal&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What's Wrong:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;ProductCard&lt;/code&gt; knows that a modal exists somewhere&lt;/li&gt;
&lt;li&gt;Parent component becomes a courier between unrelated parts&lt;/li&gt;
&lt;li&gt;Changing modal type requires editing multiple files&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It's like if every office employee delivered documents personally instead of using a shared mailbox.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Problem 2: Mediator Services as New Monoliths&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;When Outputs multiply, we create &lt;code&gt;ModalService&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="c1"&gt;// modal.service.ts&lt;/span&gt;
&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;modalSubject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Subject&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;modal$&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;modalSubject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;asObservable&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&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="nx"&gt;modalSubject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// product-card.component.ts&lt;/span&gt;
&lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;modal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ModalService&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="nf"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;()&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="nx"&gt;modal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;product-details&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Seems better, but:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Service becomes a "god object" knowing all modals&lt;/li&gt;
&lt;li&gt;Components are tightly coupled to service API&lt;/li&gt;
&lt;li&gt;Testing requires mocking entire service for one button&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In one project, our &lt;code&gt;SharedService&lt;/code&gt; grew to 1200 lines - it managed modals, tooltips, notifications, and animations. We joked that it now runs the project instead of us, but the laughter was nervous.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Case: The Spy Modal&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Several years ago we needed to add analytics for a feedback modal. The problem - it was opened from 17 places in the app. With the old pattern we had to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add &lt;code&gt;@Output() registerClick&lt;/code&gt; to 5 components&lt;/li&gt;
&lt;li&gt;Push events through 3 layers of parent components&lt;/li&gt;
&lt;li&gt;Update &lt;code&gt;AnalyticsService&lt;/code&gt; to add tracking&lt;/li&gt;
&lt;li&gt;Write 23 tests to verify event propagation&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This took 2 workdays. With &lt;a href="https://postboy.artstesh.ru" rel="noopener noreferrer"&gt;postboy&lt;/a&gt; solution - 20 minutes:&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="c1"&gt;// Opening modal with analytics&lt;/span&gt;
&lt;span class="nx"&gt;postboy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fire&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;OpenModalEvent&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;signup&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;navbar&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="c1"&gt;// Analytics context&lt;/span&gt;
&lt;span class="p"&gt;}));&lt;/span&gt;

&lt;span class="c1"&gt;// Global subscription to all modal opens&lt;/span&gt;
&lt;span class="nx"&gt;postboy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;OpenModalEvent&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&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;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;modal-open&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;source&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;No component edits - just added subscription in root module.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Why This is an Architectural Trap?&lt;/strong&gt;
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Fragility&lt;/strong&gt;: Changing one component triggers a wave of edits in others&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Testability&lt;/strong&gt;: To test a button, you need to mock a chain of services&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalability&lt;/strong&gt;: New features increase complexity exponentially&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This resembles a city without a master plan: first buildings are erected haphazardly, then they spend years clearing crooked alleys.&lt;/p&gt;

&lt;p&gt;Plus, up to a quarter of code review discussions revolve around "how to properly pass an event through component C".&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Interim Summary&lt;/strong&gt;: Angular components are like metropolis residents — they can be independent but need a "central post office" for communication. In the next part, we'll explore how to implement such an office: via custom solution, NgRx, or lightweight libraries. Spoiler: sometimes the best framework is a few dozen lines of code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 3: Backend Lessons — What Frontend Can Steal from RabbitMQ
&lt;/h2&gt;

&lt;p&gt;If components could talk, they'd ask the backend for advice. RabbitMQ, Kafka, and other brokers have been solving the same problems that plague frontend for decades. Let's "borrow" four principles to stop reinventing wheels.&lt;/p&gt;




&lt;h3&gt;
  
  
  Principle 1: Publishers Don't Know Subscribers
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;How it works in RabbitMQ:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A seller (publisher) places goods in a warehouse (broker). They don't care who takes the goods — a courier, client, or thief (just kidding).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Frontend Analogy&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;A component publishes a "User Logged In" event without knowing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Who will update the header&lt;/li&gt;
&lt;li&gt;Who will send analytics&lt;/li&gt;
&lt;li&gt;Who will show a welcome tooltip
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Before&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;authService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;login&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;tap&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;header&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;refresh&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="nx"&gt;analytics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trackLogin&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="nx"&gt;tourService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&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="c1"&gt;// How it should be&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;authService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;login&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;subscribe&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;eventBus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;UserLoggedInEvent&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;h3&gt;
  
  
  Principle 2: Messages as System Documentation
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Backend Practice:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In RabbitMQ, message schemas (e.g., using Avro) serve as living API documentation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Frontend Implementation:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Every event is a typed class:&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;class&lt;/span&gt; &lt;span class="nc"&gt;PasswordChangedEvent&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="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;email&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;sms&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="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;Now any developer can see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What data the event contains&lt;/li&gt;
&lt;li&gt;Possible field values&lt;/li&gt;
&lt;li&gt;Where it's used (via project search)&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Principle 3: Queues as Chaos Buffers
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Backend Pattern:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If a consumer service crashes, RabbitMQ preserves messages in queues until it recovers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Frontend Adaptation:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For critical events (e.g., analytics), implement retry logic:&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;class&lt;/span&gt; &lt;span class="nc"&gt;AnalyticsService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;failedEvents&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AnalyticEvent&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="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="nx"&gt;eventBus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;AnalyticEvent&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;try&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;sendToServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&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="nx"&gt;failedEvents&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Save for retry&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;h3&gt;
  
  
  Principle 4: Typing as Contract
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Backend Example:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Kafka schemas are registered in Confluent Schema Registry. Incompatible versions get blocked.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Frontend Implementation:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Use TypeScript for error prevention:&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="c1"&gt;// V1: Deprecated version&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ProductAddedEvent&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="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;productId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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="c1"&gt;// V2: New version&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ProductAddedEventV2&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="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;productId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;categoryId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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="c1"&gt;// Subscriber catches only its version&lt;/span&gt;
&lt;span class="nx"&gt;eventBus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ProductAddedEventV2&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="cm"&gt;/* ... */&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What It Looks Like in an Ideal World
&lt;/h3&gt;

&lt;p&gt;Imagine components as independent microservices:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Module A&lt;/strong&gt; publishes &lt;code&gt;CartUpdatedEvent&lt;/code&gt; with type &lt;code&gt;{ cartId: string, items: CartItem[] }&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Module B&lt;/strong&gt; subscribes and updates the cart badge&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Module C&lt;/strong&gt; listens to the same event for shipping calculations&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Module D&lt;/strong&gt; writes to LocalStorage&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;No one knows about others' existence. Changed the cart format? Just create &lt;code&gt;CartUpdatedEventV2&lt;/code&gt; — old subscribers keep working with V1.&lt;/p&gt;




&lt;h3&gt;
  
  
  Why Frontend Lags Behind?
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Synchronous Mindset&lt;/strong&gt;: "Click button → call method → get result" — this is a legacy approach.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fear of Asynchronicity&lt;/strong&gt;: Developers fear "floating" events, though it's normal in backend.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Contract Culture&lt;/strong&gt;: Frontend teams rarely document event formats, turning them into magic strings.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Real-Life Story&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;When we implemented typed events, a new developer connected the "order history" feature in a day by studying existing message classes. Previously, this required weeks of negotiations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;Backend architects have polished event-driven approaches for decades. It's time for frontend to stop stewing in its own juice and start "stealing" proven solutions. In the next part, we'll implement these principles in practice — from custom buses to ready-made tools.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 4: Practical Implementation — From Custom Solutions to Libraries
&lt;/h2&gt;

&lt;p&gt;Frontend developers often argue: "Should we build our own EventBus or use existing solutions?". The answer depends on scale. Let’s implement three variants and analyze when each fits.&lt;/p&gt;




&lt;h3&gt;
  
  
  Option 1: Custom RxJS Bus in 15 Minutes
&lt;/h3&gt;

&lt;p&gt;A basic RxJS EventBus in 20 lines of code:&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;filter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Subject&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;rxjs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;EventPayload&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;data&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EventBus&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;_events$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Subject&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;EventPayload&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nx"&gt;publish&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&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;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&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="nx"&gt;_events$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;subscribe&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&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;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&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;_events$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&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;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;T&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="c1"&gt;// Usage&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;EventBus&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;bus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subscribe&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;GREETING&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&amp;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="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="nx"&gt;bus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;GREETING&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;Hello from 1983!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Pros&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Full control&lt;/li&gt;
&lt;li&gt;0 dependencies&lt;/li&gt;
&lt;li&gt;Suitable for small projects&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No data typing&lt;/li&gt;
&lt;li&gt;Manual subscription management&lt;/li&gt;
&lt;li&gt;No Angular lifecycle support&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;When to use&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Prototypes&lt;/li&gt;
&lt;li&gt;Mini-apps (&amp;lt;15 components)&lt;/li&gt;
&lt;li&gt;Teaching Pub/Sub principles&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Option 2: NgRx as an Event Store
&lt;/h3&gt;

&lt;p&gt;NgRx is "heavy artillery" with a full toolkit:&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="c1"&gt;// actions/events.actions.ts&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;showModal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[UI] Show Modal&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;context&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;unknown&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="c1"&gt;// effects/events.effects.ts&lt;/span&gt;
&lt;span class="nx"&gt;showModal$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;actions$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nf"&gt;ofType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;showModal&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="nf"&gt;tap&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;`Modal &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; opened`&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="na"&gt;dispatch&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="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// component.ts&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;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;showModal&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;confirm&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Pros&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;DevTools with event history&lt;/li&gt;
&lt;li&gt;Integration with app state&lt;/li&gt;
&lt;li&gt;Support for complex scenarios (CQRS, sagas)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Overkill for simple tasks&lt;/li&gt;
&lt;li&gt;Learning curve&lt;/li&gt;
&lt;li&gt;Bundle size +45 KB&lt;/li&gt;
&lt;li&gt;Typing challenges&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;When to use&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enterprise applications&lt;/li&gt;
&lt;li&gt;When NgRx is already in use&lt;/li&gt;
&lt;li&gt;Complex state-driven business logic&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Option 3: Specialized Libraries
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;The &lt;a href="https://postboy.artstesh.ru" rel="noopener noreferrer"&gt;postboy&lt;/a&gt; Example&lt;/strong&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="c1"&gt;// Event definition&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ApiErrorEvent&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;PostboyGenericMessage&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="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&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="c1"&gt;// Publishing&lt;/span&gt;
&lt;span class="nx"&gt;postboy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fire&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ApiErrorEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="c1"&gt;// Subscription&lt;/span&gt;
&lt;span class="nx"&gt;postboy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ApiErrorEvent&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Error: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&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="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;When to use&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Medium to enterprise projects&lt;/li&gt;
&lt;li&gt;Microfrontends&lt;/li&gt;
&lt;li&gt;Gradual legacy code migration&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  How to Choose a Tool?
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1. Decision Map&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&amp;lt; 15 components: RxJS Subject&lt;/li&gt;
&lt;li&gt;15+ components (to infinity): &lt;a href="https://postboy.artstesh.ru" rel="noopener noreferrer"&gt;postboy&lt;/a&gt; or similar&lt;/li&gt;
&lt;li&gt;50+ components (to infinity): NgRx + additional brokers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2. 48-Hour Rule&lt;/strong&gt;:&lt;br&gt;
If you couldn't implement Pub/Sub in two days — your choice is too complex.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Scalability Test&lt;/strong&gt;:&lt;br&gt;
Try adding a reaction to an event from a completely new module. If it requires changes in 3+ places — your architecture isn't event-driven.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Case Study&lt;/strong&gt;:&lt;br&gt;
On a project with 70 components, we started with a custom solution and switched to &lt;a href="https://postboy.artstesh.ru" rel="noopener noreferrer"&gt;postboy&lt;/a&gt; after six months. It was like changing an engine mid-flight, but the event-driven architecture allowed gradual migration.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;:&lt;br&gt;
Pub/Sub isn't a silver bullet. It's like a hammer: you can drive nails or smash screens. Choose tools based on "nail size" and remember: the best architecture lets you sleep at night, not brag at meetups.&lt;/p&gt;
&lt;h2&gt;
  
  
  Part 5: When Events Become Harmful — Pub/Sub Pitfalls
&lt;/h2&gt;

&lt;p&gt;Pub/Sub is like fire: warms when controlled, burns everything when unleashed. Let's explore three scenarios where event-driven models turn from medicine to poison.&lt;/p&gt;


&lt;h3&gt;
  
  
  1. Cyclic Dependencies: Infinite Loop
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;Event &lt;code&gt;A&lt;/code&gt; triggers &lt;code&gt;B&lt;/code&gt;, &lt;code&gt;B&lt;/code&gt; triggers &lt;code&gt;C&lt;/code&gt;, and &lt;code&gt;C&lt;/code&gt; triggers &lt;code&gt;A&lt;/code&gt; again.&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="c1"&gt;// Component A&lt;/span&gt;
&lt;span class="nx"&gt;postboy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;EventC&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&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;postboy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;EventA&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// Looping&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Component B&lt;/span&gt;
&lt;span class="nx"&gt;postboy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;EventA&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&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;postboy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;EventB&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Component C&lt;/span&gt;
&lt;span class="nx"&gt;postboy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;EventB&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&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;postboy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;EventC&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;&lt;strong&gt;Why dangerous&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Infinite event loop → 100% CPU load&lt;/li&gt;
&lt;li&gt;Impossible to debug via DevTools&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add debounce (RxJS operator):
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;postboy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;EventA&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;debounceTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="cm"&gt;/* ... */&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Use inhibitor flags:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;isProcessing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;postboy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;EventA&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isProcessing&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;isProcessing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// Logic...&lt;/span&gt;
        &lt;span class="nx"&gt;isProcessing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&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;h3&gt;
  
  
  2. Memory Leaks: Ghost Subscriptions
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;Unsubscribed subscriptions in services accumulate during hot module reloading.&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;Injectable&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;AnalyticsService&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="c1"&gt;// Subscription never unsubscribed!&lt;/span&gt;
        &lt;span class="nx"&gt;eventBus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;TrackingEvent&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="cm"&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;&lt;strong&gt;Why dangerous&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Memory leaks → performance crashes&lt;/li&gt;
&lt;li&gt;"Zombie handlers" react to events after component destruction&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Angular Solution&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use takeUntilDestroyed:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;destroyRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;DestroyRef&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;eventBus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;takeUntilDestroyed&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="nx"&gt;destroyRef&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="cm"&gt;/* ... */&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;For services — manual management:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;Subscription&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;ngOnInit&lt;/span&gt;&lt;span class="p"&gt;()&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="nx"&gt;sub&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;eventBus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Event&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="cm"&gt;/* ... */&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;ngOnDestroy&lt;/span&gt;&lt;span class="p"&gt;()&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="nx"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;unsubscribe&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;h3&gt;
  
  
  3. Typing Blind Spots: Errors in the Darkness
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;The Problem&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;Untyped events become runtime time bombs.&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="c1"&gt;// Bad: Data without contract&lt;/span&gt;
&lt;span class="nx"&gt;eventBus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user_updated&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;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;123&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Alice&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Somewhere else in the codebase&lt;/span&gt;
&lt;span class="nx"&gt;eventBus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user_updated&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&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="nx"&gt;data&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;age&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// undefined → runtime crash&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why Dangerous&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Errors surface only at runtime&lt;/li&gt;
&lt;li&gt;Refactoring becomes Russian roulette&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use message classes:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserModel&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserUpdatedEvent&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;PostboyGenericMessage&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="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserModel&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&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="c1"&gt;// Type-safe subscription&lt;/span&gt;
&lt;span class="nx"&gt;postboy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;UserUpdatedEvent&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&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="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// string type guaranteed&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  When NOT to Use Pub/Sub
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Safety Rule&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;Before publishing an event, ask three questions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Are there subscribers besides me?&lt;/li&gt;
&lt;li&gt;Could this event trigger unexpected side effects?&lt;/li&gt;
&lt;li&gt;Can the problem be solved simpler via Input/Output?&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;Pub/Sub requires discipline. It's nuclear energy: properly handled gives light, mishandled causes destruction.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 6: Epilogue — Cultivating Architecture
&lt;/h2&gt;

&lt;p&gt;Software architecture isn't a blueprint carved in stone. It's a living garden where components, like plants, grow, intertwine, and occasionally require pruning. Pub/Sub isn't a magic staff, but a gardener's tool to manage chaos without suppressing it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Three Rules of Evolution
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1. Start Small&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Don't attempt to implement event-driven architecture across the entire application at once. Begin with one module where dependencies already resemble a spiderweb. Replace the most problematic &lt;code&gt;@Output()&lt;/code&gt; with an event — and watch how the architecture starts evolving on its own.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Refactor Only When Issues Arise&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If components communicate through two initialization layers — leave them untouched. As Kent Beck said: "Don't solve problems you don't have". Pub/Sub is a remedy for complexity, not a preventive vitamin.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Choose Tools Matching Scale&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A custom 20-line bus might be better than NgRx or &lt;a href="https://postboy.artstesh.ru" rel="noopener noreferrer"&gt;postboy&lt;/a&gt; for a 15-component project. But when the system grows to 200+ modules — seek solutions with typing.&lt;/p&gt;




&lt;h3&gt;
  
  
  How to Start Tomorrow
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1. Find a "Suspicious" Component&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;One that knows about five other modules. Replace one method call with an event.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Document Contracts&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Create an &lt;code&gt;events&lt;/code&gt; folder with message classes. Even if using string types — describe them in JSDoc.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Organize a "Silent Day"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Ban the team from using &lt;code&gt;@Output()&lt;/code&gt; and mediator services for a week. You'll be surprised how quickly event-driven alternatives emerge.&lt;/p&gt;




&lt;h4&gt;
  
  
  Epilogue for Skeptics
&lt;/h4&gt;

&lt;p&gt;"But events complicate debugging!" you'll say. Let me answer with a story: when we implemented event-driven architecture in our project, a new developer integrated a feature in one day that previously took a week. They simply found the right event in documentation and subscribed.&lt;/p&gt;

&lt;p&gt;Yes, events mean responsibility. Yes, they require discipline. But they also grant freedom comparable to transitioning from monarchy to democracy. You stop being a god-architect and become a gardener who only sets growth rules.&lt;/p&gt;

&lt;p&gt;Postboy — one tool in your shed. You might choose NgRx, a custom bus, or something else. The essence isn't the library, but the paradigm shift: *&lt;em&gt;stop coupling components and start describing their interaction as a contract between equals&lt;br&gt;
*&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Final Tip&lt;/strong&gt;. Next time you see a chain of three &lt;code&gt;@Output()&lt;/code&gt;s — imagine it's a weed. Uproot it, plant an event, and watch the architecture blossom.&lt;/p&gt;

&lt;p&gt;P.S. Postboy documentation — &lt;a href="https://postboy.artstesh.ru" rel="noopener noreferrer"&gt;here&lt;/a&gt;. But if you prefer to write your own EventBus, I hope this treatise inspires your heroic feat. Happy coding!&lt;/p&gt;

</description>
      <category>eventdriven</category>
      <category>angular</category>
      <category>typescript</category>
    </item>
    <item>
      <title>C# vs Angular: Universal Principles of Dependency Injection</title>
      <dc:creator>Art Stesh</dc:creator>
      <pubDate>Sat, 03 May 2025 14:00:00 +0000</pubDate>
      <link>https://dev.to/artstesh/c-vs-angular-universal-principles-of-dependency-injection-36j9</link>
      <guid>https://dev.to/artstesh/c-vs-angular-universal-principles-of-dependency-injection-36j9</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Dependency Injection (DI) is a concept so deeply ingrained in everyday programming practices that ignoring it could almost be considered a cardinal sin, on par with neglecting version control. But why has DI become so crucial?&lt;/p&gt;

&lt;p&gt;DI is one of the key principles enabling the creation of flexible and maintainable applications. The philosophy behind it revolves around freeing code from unnecessary details that tightly couple logical components. Components no longer depend on specific implementations of other parts of the system—they simply declare their needs, and DI provides the required dependencies.&lt;/p&gt;

&lt;p&gt;The goal here is not just to master a trendy technology but to explore a universal architectural tool whose concepts transcend different ecosystems. Studying DI across multiple languages and environments not only deepens your understanding of the concept itself but also broadens your perspective on system design. You’ll come to realize that, despite syntactic differences, fundamental ideas converge toward the same architectural goals.&lt;/p&gt;

&lt;p&gt;Who will benefit from this article? If you’re already familiar with .NET’s &lt;code&gt;IServiceCollection&lt;/code&gt; but have always wanted to understand Angular’s Injectors, you’re in the right place. Conversely, if you write TypeScript code but the term "Transient" leaves you puzzled—welcome aboard. We’ll explore how similar concepts adapt to two different worlds and why studying both ecosystems will help you design better applications.&lt;/p&gt;

&lt;p&gt;The aim of this piece is to demonstrate that the fundamental principles of DI remain consistent regardless of framework popularity or language-specific syntax. In short, you’ll see how elegant ideas underpin technologies as diverse as C# and Angular.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is DI? A Unified Philosophy
&lt;/h2&gt;

&lt;p&gt;Dependency Injection may seem complex at first glance, but its "magic" boils down to a simple idea: let a specialized mechanism handle the creation and management of dependencies in your application. This relieves the code of unnecessary coupling, making the application significantly more flexible and testable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Reduce Coupling?
&lt;/h3&gt;

&lt;p&gt;A primary goal of DI is &lt;strong&gt;decoupling&lt;/strong&gt;. Application components no longer rigidly depend on one another. Instead, they work with abstractions, and concrete implementations are dynamically supplied. Remember the golden rule of good architecture: &lt;em&gt;depend on interfaces, not concrete classes&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Reduced coupling means components are easier to test (dependencies can be replaced with mocks). It also simplifies extending functionality: you can swap one implementation for another without rewriting old code—just register the new dependency. This is especially important in large applications where changes require careful validation and minimal side effects.&lt;/p&gt;

&lt;h3&gt;
  
  
  Similarities in C# and Angular
&lt;/h3&gt;

&lt;p&gt;Here’s the interesting part. At first glance, C# and Angular seem like entirely different technologies: strict, OOP-oriented C# versus Angular’s modular, declarative approach. Yet both systems understand and support DI in the same way, proving the universality of this philosophy.&lt;/p&gt;

&lt;p&gt;At the core of DI in Angular and C# lies the same key idea: inversion of control. The architectural magic in both revolves around a "dependency container"—a mechanism that handles object creation, configuration, and management.&lt;br&gt;
Angular uses a powerful system of "injectors," while C# relies on IoC containers (Inversion of Control).&lt;/p&gt;

&lt;p&gt;Additionally, both approaches clearly recognize dependency lifecycles, offering flexibility: from objects created anew each time to Singleton implementations that persist for the application’s entire lifespan.&lt;/p&gt;
&lt;h2&gt;
  
  
  DI in C#: Runtime Injection Flexibility
&lt;/h2&gt;

&lt;p&gt;In the .NET ecosystem, DI centers on the &lt;code&gt;IServiceCollection&lt;/code&gt; interface for registering dependencies and the &lt;code&gt;DependencyResolver&lt;/code&gt; mechanism for retrieving them. Registered dependencies become automatically available, eliminating the need to manually specify how each object is created. Injection can occur via constructors, methods, or properties—giving you full control over how and where dependencies integrate.&lt;/p&gt;

&lt;p&gt;Why is this useful? Constructors suit mandatory dependencies, methods work for optional ones, and properties enable dependencies relevant only at specific times. All you need to do is configure the DI container correctly.&lt;/p&gt;
&lt;h3&gt;
  
  
  IoC Containers and Service Lifetime
&lt;/h3&gt;

&lt;p&gt;A major strength of DI in .NET is lifecycle management (Service Lifetime). Using &lt;code&gt;Transient&lt;/code&gt;, &lt;code&gt;Scoped&lt;/code&gt;, and &lt;code&gt;Singleton&lt;/code&gt;, you define how long an object exists and how often it’s created.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Transient&lt;/strong&gt;: A new object is created each time it’s requested. Ideal for lightweight, "disposable" dependencies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scoped&lt;/strong&gt;: An object is created once per request or application scope. Useful for database contexts or related data   within a single request.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Singleton&lt;/strong&gt;: An object is created once and persists for the application’s lifetime.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Configuring DI in ASP.NET Core
&lt;/h3&gt;

&lt;p&gt;The beauty of DI in .NET lies in its simplicity. The &lt;code&gt;ConfigureServices&lt;/code&gt; method registers dependencies in the container, making them available throughout your application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ConfigureServices&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IServiceCollection&lt;/span&gt; &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
   &lt;span class="c1"&gt;// Register dependencies with different lifetimes &lt;/span&gt;
   &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddTransient&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IMyTransientService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MyTransientService&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt; 
   &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddScoped&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IMyScopedService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MyScopedService&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt; 
   &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddSingleton&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IMySingletonService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MySingletonService&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Demonstration of Usage
&lt;/h3&gt;

&lt;p&gt;As a mini-example, let's demonstrate the use of some already registered dependency in a controller.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyController&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;IMyService&lt;/span&gt; &lt;span class="n"&gt;_myService&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

   &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;MyController&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IMyService&lt;/span&gt; &lt;span class="n"&gt;myService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;_myService&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;myService&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;

   &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;GetMessage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
   &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;_myService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetGreeting&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;The controller here focuses only on its task, while the creation and management of &lt;code&gt;IMyService&lt;/code&gt; remains the responsibility of the DI container.&lt;/p&gt;

&lt;h2&gt;
  
  
  DI in Angular: Declarative Approach with Metadata Binding
&lt;/h2&gt;

&lt;p&gt;Dependency Injection (DI) in Angular is a fundamental part of its architecture, making applications modular, flexible, and easily extensible. If you work with Angular, DI will be your constant companion—it ensures that components and services interact simply, clearly, and without surprises.&lt;/p&gt;

&lt;h3&gt;
  
  
  Basics of DI Mechanism in Angular
&lt;/h3&gt;

&lt;p&gt;Angular uses a powerful and declarative DI system based on three main pillars: &lt;code&gt;Injectors&lt;/code&gt;, &lt;code&gt;Providers&lt;/code&gt;, and &lt;code&gt;Injection Tokens&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Injectors&lt;/strong&gt; — the foundation of the entire system, a repository that manages the creation and provision of   dependencies. It handles all the "heavy lifting," leaving you only with configuration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Providers&lt;/strong&gt; — a way to instruct Angular on how to create or provide a dependency. Here, you declare: "for this interface or token, use this class or value."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Injection Tokens&lt;/strong&gt; — a solution for cases where no existing interface or class is available. They allow the use of arbitrary identifiers for dependencies.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Providers: Root, Module, and Component-Level Scopes
&lt;/h3&gt;

&lt;p&gt;The flexibility of DI in Angular is achieved through different provider visibility levels. Depending on the scope, you can specify:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;root&lt;/strong&gt; — the provider becomes available application-wide. Ideal for global services used everywhere.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;module&lt;/strong&gt; — the provider is limited to a specific module. Useful for services required within a particular feature or application section.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;component-level&lt;/strong&gt; — creates a unique dependency instance for each component. This enables data and state isolation between components.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, you can register a provider globally via &lt;code&gt;@Injectable({ providedIn: 'root' })&lt;/code&gt; or bind it to a component using the &lt;code&gt;providers&lt;/code&gt; array in &lt;code&gt;@Component&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using Decorators and Metadata
&lt;/h3&gt;

&lt;p&gt;Angular ensures dependency configuration remains declarative and intuitive. Decorators like &lt;code&gt;@Injectable&lt;/code&gt; or &lt;code&gt;@Inject&lt;/code&gt; explicitly "mark" what Angular needs to operate.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;@Injectable&lt;/code&gt; decorator indicates that a class can be used as a dependency and specifies its registration scope. For greater flexibility, &lt;code&gt;@Inject&lt;/code&gt; allows explicit token or provider specification at injection points.&lt;/p&gt;

&lt;p&gt;Dependency injection in a class is straightforward:&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-example&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;templateUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./example.component.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;ExampleService&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;ExampleComponent&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="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;exampleService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ExampleService&lt;/span&gt;&lt;span class="p"&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exampleService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getData&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;h2&gt;
  
  
  IoC Containers, C# in Angular
&lt;/h2&gt;

&lt;p&gt;The DI mechanism took care of initialization and passed the ready-made dependency to the component.&lt;/p&gt;

&lt;h2&gt;
  
  
  Unified Principles
&lt;/h2&gt;

&lt;p&gt;When it comes to Dependency Injection, it's surprising how similar the approaches are in seemingly different technology stacks like Angular and C#. Despite the differences in ecosystems and languages, both tools use unified architectural principles for building applications. Let's examine the key points.&lt;/p&gt;

&lt;h3&gt;
  
  
  IoC (Inversion of Control)
&lt;/h3&gt;

&lt;p&gt;The core idea of DI is the inversion of control (IoC). The traditional approach assumes that a class itself creates instances of its dependencies. DI changes the rules: control is now delegated to the container.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;In Angular&lt;/strong&gt;, this task is handled by the &lt;code&gt;Injector&lt;/code&gt;. It determines what, when, and where to create, ensuring components or services receive only ready-made dependencies. The code remains simple and isolated from infrastructure details.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;In C#&lt;/strong&gt;, the IoC container plays a similar role. Through it, you declare dependencies (e.g., using &lt;code&gt;IServiceCollection&lt;/code&gt;), and the system handles their creation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This transfer of control simplifies both code writing and architectural changes: classes become independent of implementation details.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scopes (Lifespan)
&lt;/h3&gt;

&lt;p&gt;Both Angular and C# DI provide flexible mechanisms for defining object "lifespans," helping manage state and limit dependency scopes.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Angular&lt;/strong&gt; offers three main scopes: &lt;code&gt;root&lt;/code&gt; (global), &lt;code&gt;module&lt;/code&gt;/&lt;code&gt;component&lt;/code&gt;, and &lt;code&gt;factory&lt;/code&gt; (local). The system automatically creates new instances or reuses existing ones based on the specified level.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;C#&lt;/strong&gt; uses &lt;code&gt;Transient&lt;/code&gt;, &lt;code&gt;Scoped&lt;/code&gt;, and &lt;code&gt;Singleton&lt;/code&gt; lifetimes. These determine whether a new object is created each time, preserved within a request, or maintained as a single application-wide instance.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Angular Scope&lt;/th&gt;
&lt;th&gt;C# Lifetime&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;root&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Singleton&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;component&lt;/code&gt;/&lt;code&gt;module&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Scoped&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;factory&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Transient&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Motivation and Testability
&lt;/h3&gt;

&lt;p&gt;Both approaches agree on another point: Dependency Injection is key to testability. Simplifying dependency substitution allows testing classes or components in isolation.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Angular&lt;/strong&gt; and npm libraries provide tools for mocking objects, replacing real dependencies with mocks to speed up testing and ensure determinism.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;C#&lt;/strong&gt; leverages mock objects and interfaces replaceable via the DI container in unit tests. Test implementations or libraries simulate any behavior.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thus, DI in both technologies minimizes component coupling, enhances modularity, and accelerates the creation of quality tests.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Implementation Differences
&lt;/h2&gt;

&lt;p&gt;Despite shared principles, DI implementations in Angular and C# differ in approach, tools, and philosophy. Each solution reflects its context: Angular focuses on client apps, while .NET targets web, desktop, and more. Let’s explore the details.&lt;/p&gt;

&lt;h3&gt;
  
  
  Resolvers and Dependency Types
&lt;/h3&gt;

&lt;p&gt;A key difference lies in how dependencies are defined and registered.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Angular&lt;/strong&gt; uses &lt;code&gt;Injection Tokens&lt;/code&gt; extensively. These unique keys explicitly identify dependencies, crucial for architectures with multiple implementations of the same interface or when default types fall short.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example:&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;MY_TOKEN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;InjectionToken&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;myToken&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;providers&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="na"&gt;provide&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MY_TOKEN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;useValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Angular DI&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This strict, flexible approach prevents runtime errors.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;C#&lt;/strong&gt; relies on interfaces and their implementations. Dependencies are registered as interface-to-class mappings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;  &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddTransient&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IMyService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MyService&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The process is linear, without tokens or additional layers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Areas of DI Application
&lt;/h3&gt;

&lt;p&gt;At the level of DI application, it becomes evident how Angular and C# differ in their approaches.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;In &lt;strong&gt;Angular&lt;/strong&gt;, DI is deeply integrated into the architecture. Developers cannot bypass it during development. Services, components, and even directives interact through injections, making DI an inseparable part of the ecosystem. The framework is fundamentally structured around this mechanism.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In &lt;strong&gt;C#&lt;/strong&gt;, DI is more of a recommended practice than a built-in language or platform feature. Developers can build projects without DI containers. However, most modern .NET frameworks (e.g., ASP.NET Core) include native DI support.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This distinction determines how systematically DI is adopted: Angular enforces a universal model, while C# offers flexibility.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dependency on Build/Runtime Execution
&lt;/h3&gt;

&lt;p&gt;Another conceptual difference lies in how dependencies are handled during compilation versus runtime.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;In &lt;strong&gt;C#&lt;/strong&gt;, dependencies are resolved dynamically at runtime. Developers define dependencies in the IoC container, and the system instantiates objects on the fly. This can lead to runtime errors (e.g., misconfigured or missing dependencies). While flexible, this approach demands vigilance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In &lt;strong&gt;Angular&lt;/strong&gt;, DI is strictly controlled at compile time due to strong typing. Tools like &lt;code&gt;Injection Tokens&lt;/code&gt;, decorators, and Angular’s compilation process detect DI issues before the app runs. For example, omitting a provider for a token will prevent the app from compiling.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This makes Angular more rigorous, reducing runtime error risks. In contrast, C#’s runtime flexibility is advantageous for dynamic or complex scenarios.&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;While Angular and C# share DI’s core architectural principles, their implementations diverge contextually. Angular emphasizes systematicity and safety through tokens, strong typing, and compile-time checks. C# prioritizes flexibility and dynamism, typical of a general-purpose platform. Recognizing these differences helps select the right tool for specific tasks.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Benefits of Learning DI in Both Ecosystems
&lt;/h2&gt;

&lt;p&gt;Mastering diverse approaches and tools builds confidence in designing and implementing complex systems. Beyond technologies, it hones critical skills.&lt;/p&gt;

&lt;h3&gt;
  
  
  Expanding Professional Horizons and Architectural Skills
&lt;/h3&gt;

&lt;p&gt;Understanding DI across ecosystems reveals multiple solutions to the same problem. It deepens knowledge of patterns like IoC (Inversion of Control), modularity, and loose coupling. Working with Angular and C# immerses developers in two domains: client-side apps with rich UIs and server-side systems with intricate logic.&lt;/p&gt;

&lt;p&gt;This knowledge extends beyond DI:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Recognizing when strict typing limits design freedom versus preventing errors.&lt;/li&gt;
&lt;li&gt;Evaluating trade-offs between runtime and compile-time solutions.&lt;/li&gt;
&lt;li&gt;Selecting optimal architectures for specific projects.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Designing Cross-Platform Architectures
&lt;/h3&gt;

&lt;p&gt;In an era where client-server boundaries blur, DI expertise in Angular and C# enables seamless cross-platform solutions.&lt;br&gt;
Examples include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A .NET backend with REST API paired with an Angular frontend, ensuring clear separation of concerns and unified dependency handling.&lt;/li&gt;
&lt;li&gt;Complex apps (e.g., backend serving web, desktop, and mobile) that avoid redundancy through combined approaches.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The result is loosely coupled, testable, and extensible architectures. Such systems are easier to maintain, scale, and hand over to teams.&lt;/p&gt;

&lt;h3&gt;
  
  
  Advancing Testing and Design Practices
&lt;/h3&gt;

&lt;p&gt;Testability is a cornerstone of modern development. DI simplifies testing by decoupling components. Learning DI logic is pivotal for designing testable systems and writing effective tests.&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;Mastering DI in Angular and C# transcends library or tool proficiency. It cultivates professional skills: architectural design, testing, and adapting best practices across platforms. Developers gain a holistic perspective, enabling them to combine strategies and solve real-world challenges effectively.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Dependency Injection (DI) is more than just a tool—it’s a development philosophy that remains consistent whether you’re working with Angular or C#. Principles like separation of concerns, inversion of control, and testability create flexible architectures and maintainable code.&lt;/p&gt;

&lt;p&gt;When working with both ecosystems, it becomes clear that DI universally strives for the same goals but achieves them differently. Angular impresses with its strict typing and deep integration, while C# excels in flexibility and architectural freedom. It’s in these nuances that the magic of working across platforms truly lies.&lt;/p&gt;

&lt;h3&gt;
  
  
  Final Thoughts
&lt;/h3&gt;

&lt;p&gt;There’s a simple truth: the more we study and compare technologies, the better we understand their strengths and weaknesses. DI teaches us to embrace complex systems and experiment with new approaches. There’s no one-size-fits-all formula here—everything depends on your tasks, vision, and the ecosystem you operate in.&lt;/p&gt;

&lt;p&gt;How does your experience with DI in C# differ from Angular? Where do you feel more freedom, and where do you encounter rigidity? Your insights are invaluable to the discussion.&lt;/p&gt;

&lt;p&gt;If you have ideas or topics you’d like to explore, don’t hesitate to share them. Dialogue strengthens us, and your experience could spark new discoveries.&lt;/p&gt;




&lt;p&gt;Thank you for reading! I’d love to hear your thoughts, questions, or suggestions—not just about DI, but about architecture in general. Let’s move forward together, advancing our knowledge and professional skills. &lt;/p&gt;

</description>
      <category>csharp</category>
      <category>angular</category>
    </item>
    <item>
      <title>Why you'll never learn all the frameworks</title>
      <dc:creator>Art Stesh</dc:creator>
      <pubDate>Mon, 28 Apr 2025 05:45:53 +0000</pubDate>
      <link>https://dev.to/artstesh/why-youll-never-learn-all-the-frameworks-570d</link>
      <guid>https://dev.to/artstesh/why-youll-never-learn-all-the-frameworks-570d</guid>
      <description>&lt;p&gt;When was the last time you felt like a real development expert? Personally, I — somewhere at the moment when I first wrote a program that ended without errors. Programming is like an endless renovation of the house you already live in. _ Even yesterday, you thought that a new roof would be the solution to all your problems. And today it turned out that there were windows with automatic heating, and without them the house is not a house at all. And, of course, all the neighbors have already installed such devices._&lt;/p&gt;

&lt;p&gt;When I first started writing code, it seemed that everything was arranged quite simply. I've learned the language, figured out a couple of libraries, and written a few algorithms, and you're already a great programmer. But over time, this feeling disappeared. Now I go to Telegram or read another tech blog, and it seems to me that everyone is discussing something that I haven't figured out yet: a new framework like Bun has been released.js, updated language specification (JavaScript ECMAScript 2024), released Webpack 6. And someone managed to test some new linter. And against the background of these bright changes, I look at my work project and wonder: and whether I can integrate all this ultra-modern stack into my projects, and whether it is necessary at all.&lt;/p&gt;

&lt;h3&gt;
  
  
  Programmers as athletes
&lt;/h3&gt;

&lt;p&gt;One of the most challenging(and interesting) aspects of our profession is its inability to stop. If there's one constant in development, it's the speed of change. We live in an industry growing faster than any other — every month:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;New tools are coming (like Vite &amp;amp;&amp;amp; TurboPack),&lt;/li&gt;
&lt;li&gt;Someone finds problems in existing approaches (for example, problems with the scalability of old monoliths),&lt;/li&gt;
&lt;li&gt;And someone offers fundamentally new architectural solutions (such as the popularization of microservices or "serverless-first").&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These innovations make us part of incredible progress, but also part of the race. Only this race often turns out to be far from about technology — it &lt;strong&gt;is about ourselves&lt;/strong&gt;. It's like you were comparing yourself yesterday and asking the same questions: How much more do I need to know? How quickly can I learn a new technology? Will I be able to understand in a week what others have been studying for months?&lt;/p&gt;

&lt;p&gt;And this constant comparison — as in professional sports-can either stimulate or destroy success.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Yes, we live in a world where we are always under pressure from deadlines and new frameworks. But admit it: it's cool to argue with your colleagues about whether your project needs a new "lightweight" tool that you'll regret for the next quarter.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Framework of the week. Or how technology is moving faster than us
&lt;/h3&gt;

&lt;p&gt;Every month there are not just new technologies, but "blindingly new" ones — so much so that it seems as if your project is doomed without them. Everyone has examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Someone implemented Next.js also claims that without server-side rendering (#SSR), modern sites are no longer relevant.&lt;/li&gt;
&lt;li&gt;Someone switched to SvelteKit and said that its performance impact surpassed the project on React.&lt;/li&gt;
&lt;li&gt;Or remember the hype around Deno, which was supposedly supposed to replace the good old one Node.js. Do you use it?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;New 'tech killers' &lt;em&gt;appear faster than you can finish your coffee and open the tab with their dock&lt;/em&gt;. And by the time you take the last sip, other material is already appearing with screaming headlines about the fact that there was an even more ultimatum competitor for the "killer". Remember how NoSQL replaced all these outdated and outdated relational database approaches, creating a beautiful world without PostgeSQL/MSSQL/...? And how did sharp Blazor destroy JS, TS, and indeed all front-end development?&lt;/p&gt;

&lt;p&gt;The volume of docs of new frameworks released in 2024 cannot be reread in a year, and none of us knows them all. No one. Even the most popular tech bloggers who give great conference presentations don't have time to jump on every tech train.&lt;/p&gt;

&lt;p&gt;The life of a programmer is a constant choice: what to learn and what to skip. Kubernetes looks like a complex monster, but do you need it in your real work? Maybe right now it's easier to focus on deepening the knowledge in your stack or on mastering TypeScript?&lt;/p&gt;

&lt;p&gt;At some point, I realized that knowledge overlaps in layers. If you have a good base — it won't be difficult for you to understand new tools, because the concepts remain the same. It's funny, but &lt;strong&gt;the more experience you have in programming, the slower your knowledge starts to become outdated.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Pressure Formula: Why we always feel like we're falling behind
&lt;/h3&gt;

&lt;p&gt;The key problem that most developers face is the perception of time. Deadlines are pressing on you. This is superimposed on the perception of learning: it seems to us that the new tools should be mastered &lt;strong&gt;immediately&lt;/strong&gt;, because "this should have been done yesterday". And if you spend time on GitHub, Hacker News, or Reddit, there are all success stories around:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Someone launched a small software product that made millions.&lt;/li&gt;
&lt;li&gt;Someone posted a library that collected tens of thousands of stars.&lt;/li&gt;
&lt;li&gt;And someone implemented algorithms that you didn't even know in theory.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But this is an illusion. Real life isn't like that. No one posts GIFs as they spend 3 days trying to figure out why &lt;code&gt;docker-compose&lt;/code&gt; doesn't work for them. No one posts about banging their head against the wall for 2 hours before the test database started. We only see the result, not the path. And we compare ourselves to this "edited image".&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;GitHub is like Instagram for programmers; only instead of beautiful photos, there are projects with perfect code that make you forget that real life is a little less glamorous. No one puts out stories "five hours of debugging, and the reason was in my cache".&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In this race, it is important to understand one thing: this approach destroys everything. If you constantly run just to "catch up", then you will get tired faster than you will succeed.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to handle this race
&lt;/h3&gt;

&lt;p&gt;I don't think that any of the programmers can completely get out of this feeling. We will always be passionate about something, concerned about something in our work. But I've learned to treat it differently.&lt;/p&gt;

&lt;p&gt;First — I don't compare myself to other people anymore. There is no "perfect engineer" position to strive for. Even if you meet a cool developer who created a bunch of libraries, they also started somewhere. His way is his way, and yours is yours.&lt;/p&gt;

&lt;p&gt;Second — appreciate your progress. One of the main principles for me was the constant "recording of small victories". Yes, today I didn't learn a new library or implement a supernova tool, but I figured out another bug, optimized the module, or closed several tasks. This is already a reason to meet the needs.&lt;/p&gt;

&lt;p&gt;Finally, the job of a programmer is more about curiosity than commitment. We don't have to "learn all the technologies" or "become the best at everything at once". We must always remain curious and explore the world. This is the best thing we can do for ourselves and this profession.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to get out of the "race"
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Do not rush to master everything at once&lt;/strong&gt;. Add technologies to your list, but don't try to dive into every topic. New tools always seem irreplaceable, but usually only 10–20% of them actually become standards.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compare yourself only with past experience&lt;/strong&gt;. Have you learned how to use a new tool? Did you solve the problem easier? This is your progress.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Get inspired, but don't focus on other people's charts&lt;/strong&gt;. Everyone has their own "race". Some people write neural networks by the age of 20, while others have a career built up by the age of 30–40, but it leads to a deep understanding of fundamental knowledge.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Learn the basics of. This will slow down the obsolescence of your knowledge.&lt;/strong&gt; If you rely on the principles of development (SOLID, algorithms and data structures, asynchrony), then any framework will be much easier to master. After all, concepts don't change.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Instead of concluding
&lt;/h3&gt;

&lt;p&gt;I like to think that programming is a profession in which you will learn and grow until the very end of life. It's a never-ending race with yourself. But it's not about being the best at some conferences or showing off in interviews. It's about asking yourself every day: "What new things can I understand and create?"&lt;/p&gt;

&lt;p&gt;But if you're going to admit it's a race, then imagine that it's a race for fun and not to get to the finish line first. Look around you: you are a participant in an incredible marathon, in which it is not so much important for us to win, but to learn how to enjoy running.&lt;/p&gt;

&lt;p&gt;Yes, we will always be a little behind reality, but this is not a reason to stop. After all, the best thing about this job is the learning process.&lt;br&gt;
Everything you do is a step forward. As one of my colleagues said:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"If you still ask questions, it means that you continue to grow and learn — and this is the main sign of a good programmer".&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>programming</category>
    </item>
    <item>
      <title># The Third Step Into the World of RxJS: Combining Streams in RxJS</title>
      <dc:creator>Art Stesh</dc:creator>
      <pubDate>Sat, 19 Apr 2025 14:00:00 +0000</pubDate>
      <link>https://dev.to/artstesh/-the-third-step-into-the-world-of-rxjs-combining-streams-in-rxjs-42i9</link>
      <guid>https://dev.to/artstesh/-the-third-step-into-the-world-of-rxjs-combining-streams-in-rxjs-42i9</guid>
      <description>&lt;p&gt;RxJS is a powerful tool, but it can also be tricky. Many beginners who have mastered basic operators like &lt;code&gt;map&lt;/code&gt;, &lt;code&gt;filter&lt;/code&gt;, and perhaps even &lt;code&gt;take&lt;/code&gt;, start feeling confident. Then they encounter tasks where they need to combine multiple streams simultaneously... and that's where it all begins to fall apart. Panic sets in. Should you use &lt;code&gt;combineLatest&lt;/code&gt;, &lt;code&gt;forkJoin&lt;/code&gt;, &lt;code&gt;merge&lt;/code&gt;, &lt;code&gt;zip&lt;/code&gt;? What do you do when data arrives at different speeds? This material is for those feeling lost at this stage. Let’s calmly and methodically figure it out together.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Why Is This Important?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Your first challenge with combination operators is that they seem to speak their own language. If you think of an Observable as a stream of events, then combination operators are the conductors orchestrating multiple streams, aligning them in sync, and producing a "new melody."&lt;/p&gt;

&lt;p&gt;Imagine a classic scenario: you're building a form in Angular, and you need to show a "Submit" button only when all fields are validated. Or you need to merge data from two APIs. These are typical use cases where combination operators become your main instrument.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;When to Use Which Operator?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;RxJS provides several tools to merge data from different sources. However, despite the abundance of articles on this topic, developers in real projects often misunderstand how to apply them correctly. Let’s examine the most popular combination operators with real-world examples.&lt;/p&gt;

&lt;p&gt;Imagine this scenario:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Factory A&lt;/strong&gt; produces components (e.g., every hour). This is one stream of data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Factory B&lt;/strong&gt; sends requests for components as they are ready for assembly. This is a second stream of data.&lt;/li&gt;
&lt;li&gt;As operators, we need to organize the supply of components for assembly based on different conditions. Each RxJS operator dictates its own method for managing this process.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;1. zip — "One to One"&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;zip&lt;/code&gt; operator enforces strict synchronization. We wait for Factory A to produce a component and simultaneously for Factory B to request that specific component. Only then is the component passed for assembly. No component will be sent until a pair is matched: "ready component + request for the component."&lt;/p&gt;

&lt;h4&gt;
  
  
  When to Use:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Multiple streams logically depend on one another.&lt;/li&gt;
&lt;li&gt;You need to ensure strict synchronization of streams in order.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Production Example:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Factory A produces components every 3 hours.&lt;/li&gt;
&lt;li&gt;Factory B sends requests for components every 2 hours.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Outcome: Each pair of "component + request" is sent to assembly. If a component is produced before the request, it waits until a signal to dispatch it arrives.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code Example in TypeScript:&lt;/strong&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;zip&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;rxjs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;take&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;rxjs/operators&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Factory A (produces components every 3 seconds)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;factoryA$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;`Component &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;i&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;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="c1"&gt;// Factory B (requests for components every 2 seconds)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;factoryB$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;`Request for Component &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;i&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;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="c1"&gt;// Combine one component from A with one request from B&lt;/span&gt;
&lt;span class="nf"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;factoryA$&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;factoryB$&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;take&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(([&lt;/span&gt;&lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;request&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;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; paired with &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;component&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="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Output:&lt;/span&gt;
&lt;span class="c1"&gt;// Request for Component 1 paired with Component 1&lt;/span&gt;
&lt;span class="c1"&gt;// Request for Component 2 paired with Component 2&lt;/span&gt;
&lt;span class="c1"&gt;// Request for Component 3 paired with Component 3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  &lt;strong&gt;Performance of &lt;code&gt;zip&lt;/code&gt;&lt;/strong&gt;
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The Number of Streams Matters&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
&lt;code&gt;zip&lt;/code&gt; can combine not just two but multiple streams. However, as the number of streams grows, performance can degrade because the operator has to monitor each stream and wait for values to align before producing a new combination. This is particularly noticeable when streams emit data at different rates or have delays.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Data Buffering&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
If one stream produces values faster than another, &lt;code&gt;zip&lt;/code&gt; will need to buffer these values (temporarily store them) until data from all streams is ready. This may require more memory when handling streams with uneven data flow. For instance, if one stream emits millions of items quickly, &lt;code&gt;zip&lt;/code&gt; will buffer them until the corresponding data from the other streams arrives.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Pitfalls When Using &lt;code&gt;zip&lt;/code&gt;&lt;/strong&gt;
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Sensitivity to Value Counts&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
If streams emit a significantly different number of items, the operator will only work up to the point where one of the streams runs out of values. Any additional items from other streams will not be processed after one stream completes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Compatibility with Infinite Streams&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
If all input streams are infinite (e.g., &lt;code&gt;interval&lt;/code&gt; or UI events) and there’s no mechanism to terminate them, the subscriber will never complete. This can result in memory leaks or hanging processes.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;More Advanced Features of &lt;code&gt;zip&lt;/code&gt;&lt;/strong&gt;
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Using a Transformation Function&lt;/strong&gt;:
By default, &lt;code&gt;zip&lt;/code&gt; returns an array of synchronized values, but you can specify a function to immediately shape the result into the desired format.
&lt;strong&gt;Example:&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&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;zip&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;of&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;rxjs&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;stream1$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;30&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;stream2$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nf"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stream1$&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;stream2$&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&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="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 10, 40, 90&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Output:&lt;/span&gt;
&lt;span class="c1"&gt;// 10&lt;/span&gt;
&lt;span class="c1"&gt;// 40&lt;/span&gt;
&lt;span class="c1"&gt;// 90&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Recommendations for Use&lt;/strong&gt;
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Add Protection Against Infinite Streams&lt;/strong&gt;:
Use limiting operators (&lt;code&gt;take&lt;/code&gt;, &lt;code&gt;takeUntil&lt;/code&gt;) to prevent application hangs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitor Stream Frequencies&lt;/strong&gt;:
If one stream is significantly "slower" than another, calculate delays properly to avoid inefficient waiting. In some cases, it might be better to replace &lt;code&gt;zip&lt;/code&gt; with other operators like &lt;code&gt;combineLatest&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consider Completion Behavior&lt;/strong&gt;:
Explicitly manage completion or handle cases where streams emit different amounts of items.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;zip&lt;/code&gt; isn't just an operator that "stitches" streams together. It's a synchronization tool tailored for strictly ordered scenarios where the structure of the data between streams matters. However, keep in mind its sensitivity to completion, buffering, and potential delays. To effectively utilize &lt;code&gt;zip&lt;/code&gt;, it’s crucial to understand each stream's behavior and account for their limitations.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;2. combineLatest — "Working with What's Available"&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;combineLatest&lt;/code&gt; focuses on the current state of multiple streams. It emits a value only after all its sources have produced at least one value, and then updates anytime any of the streams emits new data.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;combineLatest&lt;/code&gt; waits for the first value from all sources before starting to work. Then, it emits a new combination of data whenever any of the streams produces updated data. This means that for every new request from Factory B, the &lt;strong&gt;current latest component&lt;/strong&gt; from Factory A is used immediately.&lt;/p&gt;

&lt;h4&gt;
  
  
  When to Use:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;You need to track the state of multiple sources simultaneously.&lt;/li&gt;
&lt;li&gt;Tasks related to user input or application states.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Output: As soon as there’s a new update from B (a request), the &lt;strong&gt;current state of a component&lt;/strong&gt; from A is taken and dispatched immediately.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TypeScript Code Example:&lt;/strong&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;combineLatest&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;rxjs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;take&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;rxjs/operators&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Factory A (components every 3 seconds)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;factoryA$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;`Component &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;i&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;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="c1"&gt;// Factory B (requests every 2 seconds)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;factoryB$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;`Request for Component &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;i&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;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="c1"&gt;// Each new request uses the latest state of components&lt;/span&gt;
&lt;span class="nf"&gt;combineLatest&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;factoryA$&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;factoryB$&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;take&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(([&lt;/span&gt;&lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;request&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;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; paired with &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;component&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="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Output:&lt;/span&gt;
&lt;span class="c1"&gt;// Request for Component 1 paired with Component 1&lt;/span&gt;
&lt;span class="c1"&gt;// Request for Component 2 paired with Component 1&lt;/span&gt;
&lt;span class="c1"&gt;// Request for Component 3 paired with Component 2&lt;/span&gt;
&lt;span class="c1"&gt;// Request for Component 4 paired with Component 2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  &lt;strong&gt;Performance of &lt;code&gt;combineLatest&lt;/code&gt;&lt;/strong&gt;
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Buffering and Memory&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
&lt;code&gt;combineLatest&lt;/code&gt; keeps the latest value from each source in memory. In most cases, this doesn’t impose serious constraints, but for streams emitting large objects (e.g., arrays or JSON data), it might impact performance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Handling "Noisy" Streams&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
If one stream emits data too frequently (e.g., a mouse movement stream), &lt;code&gt;combineLatest&lt;/code&gt; will frequently recalculate the result, even if the other stream remains unchanged.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Recommendation&lt;/strong&gt;: For noisy streams, use operators like &lt;code&gt;throttleTime&lt;/code&gt; or &lt;code&gt;debounceTime&lt;/code&gt; to suppress excess events and avoid processing overload.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Pitfalls of &lt;code&gt;combineLatest&lt;/code&gt;&lt;/strong&gt;
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Unpredictable Behavior with Missing Values&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
If at least one of the streams hasn’t emitted a value, &lt;code&gt;combineLatest&lt;/code&gt; &lt;strong&gt;will not publish anything&lt;/strong&gt;. This means that a stream that always "stays silent" can block the entire operation. This can be unexpected for beginners.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Performance with a High Number of Streams&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
&lt;code&gt;combineLatest&lt;/code&gt; can work with multiple streams, but performance drops significantly when trying to combine dozens of them. The reason is that, with each change, all combinations must be recalculated and reassembled.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Unexpected Failures in Real Applications&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
In applications where data comes from external APIs, &lt;code&gt;combineLatest&lt;/code&gt; can stop working unexpectedly if one API source suddenly goes silent. For example, if a service returns an HTTP error, that stream completes, making the combined stream useless.&lt;br&gt;
&lt;strong&gt;Solution&lt;/strong&gt;: Add error handling using operators like &lt;code&gt;catchError&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Hidden Features of &lt;code&gt;combineLatest&lt;/code&gt;&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Using Custom Transform Functions&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
Instead of receiving an array of values, you can transform the result directly using a custom function.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;combineLatest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;of&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;rxjs&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;width$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&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;height$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nf"&gt;combineLatest&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;width$&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;height$&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;area&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;`Area: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;area&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="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Output:&lt;/span&gt;
&lt;span class="c1"&gt;// Area: 20000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;combineLatest&lt;/code&gt; is an incredibly useful operator for working with data streams where the current state of all sources is essential. However, its use requires careful attention: pitfalls such as delays, inability to emit when a stream remains silent, or performance limitations can unexpectedly lead to bugs. To avoid such issues, always assess the emission frequencies of streams, their completion, and start with initial values (&lt;code&gt;startWith&lt;/code&gt;). This will make your applications reliable and predictable.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;3. forkJoin — "All at Once"&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;forkJoin&lt;/code&gt; takes multiple streams, waits for all of them to complete, and then returns a single final value. If even one stream doesn’t emit or doesn’t complete, no result will be emitted.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;forkJoin&lt;/code&gt; waits for ALL streams to complete and only then provides their &lt;strong&gt;latest&lt;/strong&gt; results as a final list. In production terms, this means we’ll wait for Factory A to finish producing ALL components &lt;strong&gt;and&lt;/strong&gt; for Factory B to send all the requests before processing everything at once.&lt;/p&gt;

&lt;h4&gt;
  
  
  When to Use:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;You need a &lt;em&gt;single result&lt;/em&gt; from multiple sources.&lt;/li&gt;
&lt;li&gt;Ideal for API requests, when you need to wait for all responses.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Production Example:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Factory A finishes producing all components.&lt;/li&gt;
&lt;li&gt;Factory B sends all requests.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Output: Processing begins only after both factories complete their operations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TypeScript Code Example:&lt;/strong&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;forkJoin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;interval&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;rxjs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;take&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;map&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;rxjs/operators&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Factory A (component production)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;factoryA$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;i&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;span class="nf"&gt;take&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="c1"&gt;// Factory B (requests for components)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;factoryB$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;i&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;span class="nf"&gt;take&lt;/span&gt;&lt;span class="p"&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;// Start processing only after both streams complete&lt;/span&gt;
&lt;span class="nf"&gt;forkJoin&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;factoryA$&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;factoryB$&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(([&lt;/span&gt;&lt;span class="nx"&gt;details&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;requests&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;`Processed data: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;details&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; components ready for &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; requests`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Output:&lt;/span&gt;
&lt;span class="c1"&gt;// Processed data: 3 components ready for 2 requests&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Conclusion:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;code&gt;forkJoin&lt;/code&gt; is perfectly suited for tasks where only completed data matters. For instance, it’s great for batch processing after preparation.&lt;/p&gt;


&lt;h2&gt;
  
  
  &lt;strong&gt;Performance and Optimization&lt;/strong&gt;
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Issue with Large Streams:&lt;/strong&gt;
If one of the attached streams generates a large amount of data before completing, it can place significant load on memory since each stream allocation requires resources until completion.&lt;/li&gt;
&lt;/ol&gt;


&lt;h2&gt;
  
  
  &lt;strong&gt;Pitfalls of &lt;code&gt;forkJoin&lt;/code&gt;&lt;/strong&gt;
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Not Suitable for Infinite Streams:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
If any of the streams in the set are infinite (e.g., &lt;code&gt;fromEvent&lt;/code&gt;, &lt;code&gt;interval&lt;/code&gt;), &lt;code&gt;forkJoin&lt;/code&gt; will never emit anything. This is not an error but can be an unexpected behavior.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Challenges with Error Handling:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
One major challenge is that if any stream throws an error (&lt;code&gt;error&lt;/code&gt;), the results of all other streams are lost. This might be undesirable in scenarios where partial success is significant.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Hidden Features of &lt;code&gt;forkJoin&lt;/code&gt;&lt;/strong&gt;
&lt;/h2&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Using an Object Instead of an Array:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;code&gt;forkJoin&lt;/code&gt; supports object syntax, which can be convenient for working with REST APIs or associative structures.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&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;forkJoin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;of&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;rxjs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;delay&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;rxjs/operators&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

   &lt;span class="c1"&gt;// Simulating three data sources as objects:&lt;/span&gt;
   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Ivan&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&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;of&lt;/span&gt;&lt;span class="p"&gt;([{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;101&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;total&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;102&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;total&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;450&lt;/span&gt; &lt;span class="p"&gt;}]).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1500&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;notifications$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Notification 1&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;Notification 2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

   &lt;span class="c1"&gt;// Using an object instead of an array:&lt;/span&gt;
   &lt;span class="nf"&gt;forkJoin&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
     &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user$&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="na"&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="na"&gt;notifications&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;notifications$&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Merged data:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="p"&gt;});&lt;/span&gt;
   &lt;span class="c1"&gt;// Output:&lt;/span&gt;
   &lt;span class="c1"&gt;// Merged data:&lt;/span&gt;
   &lt;span class="c1"&gt;// {&lt;/span&gt;
   &lt;span class="c1"&gt;//   user: { id: 1, name: 'Ivan' },&lt;/span&gt;
   &lt;span class="c1"&gt;//   orders: [{ id: 101, total: 300 }, { id: 102, total: 450 }],&lt;/span&gt;
   &lt;span class="c1"&gt;//   notifications: ['Notification 1', 'Notification 2']&lt;/span&gt;
   &lt;span class="c1"&gt;// }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Working with objects instead of arrays makes the code more readable, especially in scenarios involving different types of data (e.g., responses from various APIs). Instead of referencing values by array indexes (&lt;code&gt;result[0]&lt;/code&gt;, &lt;code&gt;result[1]&lt;/code&gt;), you can refer to the object keys (&lt;code&gt;result.user&lt;/code&gt;, &lt;code&gt;result.orders&lt;/code&gt;).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;forkJoin&lt;/code&gt; is an excellent tool for managing parallel processing and combining results. However, its strict requirement for stream completion imposes some limitations. To avoid unexpected errors, always consider stream completion, use error handling (&lt;code&gt;catchError&lt;/code&gt;), and add constraints (&lt;code&gt;take&lt;/code&gt;, &lt;code&gt;timeout&lt;/code&gt;). This approach will allow you to use &lt;code&gt;forkJoin&lt;/code&gt; reliably and effectively in most scenarios.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  &lt;strong&gt;4. merge — "Send Everything Immediately"&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;merge&lt;/code&gt; combines streams but emits items as soon as they arrive. Unlike &lt;code&gt;combineLatest&lt;/code&gt;, it doesn’t wait for all sources.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;merge&lt;/code&gt; simply merges all events from the streams into a single flow and emits them in the order they are received. In production, this means that as soon as a component is ready or a request arrives, it is immediately processed, without concern for synchronization.&lt;/p&gt;
&lt;h4&gt;
  
  
  When to Use:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;You need to combine events from multiple sources, but the order of their appearance isn’t important.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Production Example:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Factory A produces components every 3 hours.&lt;/li&gt;
&lt;li&gt;Factory B sends requests every 2 hours.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Output: Any event from A or B is processed immediately.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TypeScript Example:&lt;/strong&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;merge&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;rxjs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;take&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;rxjs/operators&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Factory A (producing components)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;factoryA$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;`Component &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;i&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;span class="s2"&gt; is ready`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;take&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="c1"&gt;// Factory B (requests for components)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;factoryB$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;`Request for Component &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;i&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;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;take&lt;/span&gt;&lt;span class="p"&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;// All events are processed in order of arrival&lt;/span&gt;
&lt;span class="nf"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;factoryA$&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;factoryB$&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&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="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Output (example):&lt;/span&gt;
&lt;span class="c1"&gt;// Request for Component 1&lt;/span&gt;
&lt;span class="c1"&gt;// Component 1 is ready&lt;/span&gt;
&lt;span class="c1"&gt;// Request for Component 2&lt;/span&gt;
&lt;span class="c1"&gt;// Component 2 is ready&lt;/span&gt;
&lt;span class="c1"&gt;// Component 3 is ready&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Working Features&lt;/strong&gt;
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Simultaneous Merging of Multiple Streams&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
Unlike &lt;code&gt;zip&lt;/code&gt; or &lt;code&gt;forkJoin&lt;/code&gt;, &lt;code&gt;merge&lt;/code&gt; does not depend on the sequence or frequency of data emissions from different streams. It simply publishes values &lt;strong&gt;as soon as they arrive.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Does Not Wait for All Streams to Complete&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
&lt;code&gt;merge&lt;/code&gt; continues to operate as long as at least one source stream remains active. The resulting stream completes only when all input Observables have completed.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Stream Competition&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
If values from multiple streams are emitted at the same time, they will be processed in the order they actually arrive (by timestamp).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Operator Parameters&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;concurrent&lt;/strong&gt; (default is &lt;code&gt;Number.POSITIVE_INFINITY&lt;/code&gt;):
This parameter determines the maximum number of streams that can be processed simultaneously.
If the specified number is exceeded, the remaining Observables will wait for the currently active ones to complete.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Pitfalls&lt;/strong&gt;
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Overload When Working with Infinite Streams&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
If &lt;code&gt;merge&lt;/code&gt; is merging infinite streams (like &lt;code&gt;interval&lt;/code&gt;, &lt;code&gt;fromEvent&lt;/code&gt;) that generate data too frequently, it can cause processing overload. This is especially critical when multiple such "noisy" streams are merged.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Solution&lt;/strong&gt;: Use event frequency limiting operators like &lt;code&gt;throttleTime&lt;/code&gt;, &lt;code&gt;debounceTime&lt;/code&gt;, or manually set the &lt;code&gt;concurrent&lt;/code&gt; parameter to reduce the load.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Premature Stream Closure&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
If all input streams complete but one of them throws an error (&lt;code&gt;error&lt;/code&gt;), &lt;code&gt;merge&lt;/code&gt; will terminate with an error, and the data from other completed streams will be lost.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Solution&lt;/strong&gt;: Use &lt;code&gt;catchError&lt;/code&gt; to handle errors in each stream independently without terminating the main stream.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Complexity in Handling Concurrent Streams&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
With a large number of streams operating simultaneously, the order in which &lt;code&gt;merge&lt;/code&gt; outputs the data may become unpredictable. While logical, this behavior can cause confusion if you expected the values to appear in the same order as with &lt;code&gt;concat&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Interesting Aspects of &lt;code&gt;merge&lt;/code&gt;&lt;/strong&gt;
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Handling the Processing Order Using &lt;code&gt;concurrent&lt;/code&gt;&lt;/strong&gt;:
The &lt;code&gt;concurrent&lt;/code&gt; option allows you to limit the number of streams processed simultaneously. This is useful when combining resource-heavy processes like HTTP requests.
&lt;strong&gt;Example:&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&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;merge&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;of&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;rxjs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;delay&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;rxjs/operators&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;stream1$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;of&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="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&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;stream2$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;of&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="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1500&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;stream3$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;of&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="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

   &lt;span class="nf"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stream1$&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;stream2$&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;stream3$&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&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="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

   &lt;span class="c1"&gt;// Output:&lt;/span&gt;
   &lt;span class="c1"&gt;// A&lt;/span&gt;
   &lt;span class="c1"&gt;// C&lt;/span&gt;
   &lt;span class="c1"&gt;// B&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Explanation:&lt;/strong&gt; Here, only &lt;strong&gt;two streams&lt;/strong&gt; will be processed simultaneously. As soon as one finishes, the next stream starts, maintaining the queue.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Performance&lt;/strong&gt;
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Parallel Performance&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
&lt;code&gt;merge&lt;/code&gt; excels at performance because it processes data from all sources &lt;strong&gt;in parallel&lt;/strong&gt;. This makes it an ideal choice when there are no constraints on the order of event processing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Resource Intensity of Streams&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
Streams generating a large quantity of data can strain memory and CPU because each stream operates independently. It’s important to consider the &lt;code&gt;concurrent&lt;/code&gt; parameter to manage simultaneous execution.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Sensitivity to Event Frequency&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
If streams are "noisy" (e.g., a stream generating mouse movement events), the resulting merged stream may become overloaded. Therefore, it is important to use limiting operators to optimize the load.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;blockquote&gt;
&lt;p&gt;The &lt;code&gt;merge&lt;/code&gt; operator is simple and versatile yet packed with powerful functionality. It is perfectly suited for tasks requiring parallel data processing, but it demands careful resource management when dealing with frequent or infinite streams. Use it when event order doesn’t matter, and always optimize load by limiting event frequency and the number of simultaneously processed streams (&lt;code&gt;concurrent&lt;/code&gt;).&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;4. concat — "First Come, First Served"&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;concat&lt;/code&gt; operator in RxJS offers a simple and intuitive way to process multiple streams &lt;strong&gt;sequentially&lt;/strong&gt;, one after another. Unlike &lt;code&gt;merge&lt;/code&gt;, which works in parallel, &lt;code&gt;concat&lt;/code&gt; processes the next stream only after the previous stream has completed. It can be thought of as a "queue" of Observables.&lt;/p&gt;

&lt;p&gt;Factory B will only start sending requests after the production of components in Factory A is fully completed.&lt;/p&gt;

&lt;h4&gt;
  
  
  When to Use:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;When you need to ensure the sequential execution of streams without risking data overlap.&lt;/li&gt;
&lt;li&gt;For tasks where data logically depends on one another (e.g., step-by-step processing, sequential API requests).&lt;/li&gt;
&lt;li&gt;When simultaneous data processing (like in &lt;code&gt;merge&lt;/code&gt;) is unnecessary or unacceptable.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Production Example:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Factory A produces 3 components (each taking 3 hours to complete).&lt;/li&gt;
&lt;li&gt;Factory B starts sending requests only after Factory A has finished production.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;TypeScript Code Example:&lt;/strong&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;concat&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;rxjs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;take&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;rxjs/operators&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Factory A (production of components)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;factoryA$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;`Component &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;i&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;span class="s2"&gt; is ready`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nf"&gt;take&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Produces 3 components&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Factory B (processing requests for components)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;factoryB$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;`Request for component &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;i&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;span class="s2"&gt; processed`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nf"&gt;take&lt;/span&gt;&lt;span class="p"&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;// Processes 2 requests&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Run production and requests sequentially&lt;/span&gt;
&lt;span class="nf"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;factoryA$&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;factoryB$&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&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="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Expected Output (approximate, considering timing):&lt;/span&gt;
&lt;span class="c1"&gt;// After 3 seconds: Component 1 is ready&lt;/span&gt;
&lt;span class="c1"&gt;// After 6 seconds: Component 2 is ready&lt;/span&gt;
&lt;span class="c1"&gt;// After 9 seconds: Component 3 is ready&lt;/span&gt;
&lt;span class="c1"&gt;// After 11 seconds: Request for component 1 processed&lt;/span&gt;
&lt;span class="c1"&gt;// After 13 seconds: Request for component 2 processed&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  &lt;strong&gt;Working Features&lt;/strong&gt;
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Strict Sequence&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
The main feature of &lt;code&gt;concat&lt;/code&gt; is the strict sequential order of processing streams. First, data from the first Observable is processed, then, after it completes, the next stream is activated, and so on.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Waits for Completion&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
Each stream must complete (&lt;code&gt;complete&lt;/code&gt;) before the operator moves to the next one. This makes &lt;code&gt;concat&lt;/code&gt; particularly useful for creating chains of sequential operations.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Blocking by Infinite Streams&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
If there’s an infinite stream (like &lt;code&gt;interval&lt;/code&gt; or &lt;code&gt;fromEvent&lt;/code&gt;), it will block the execution of the rest of the chain since it will never complete.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;No Limit on Number of Streams&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
&lt;code&gt;concat&lt;/code&gt; can combine any number of Observables, provided either through an array, manually, or by using the &lt;code&gt;arguments&lt;/code&gt; operator.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Pitfalls&lt;/strong&gt;
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Using Infinite Streams&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
If one of the Observables in &lt;code&gt;concat&lt;/code&gt; generates infinite data (&lt;code&gt;interval&lt;/code&gt;, &lt;code&gt;fromEvent&lt;/code&gt;, etc.), the next stream will never be triggered because the current one won’t complete.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Solution&lt;/strong&gt;: Use limiting operators like &lt;code&gt;take&lt;/code&gt; or &lt;code&gt;takeUntil&lt;/code&gt; to ensure the infinite stream eventually completes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Error Handling&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
If one of the Observables throws an error (&lt;code&gt;error&lt;/code&gt;), the entire &lt;code&gt;concat&lt;/code&gt; chain will terminate with an error, and no subsequent streams will be executed.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Solution&lt;/strong&gt;: Handle errors locally using &lt;code&gt;catchError&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Complexity in Handling Competition&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
While &lt;code&gt;concat&lt;/code&gt; ensures strict order of execution, if you mismanage resource usage or processing delays, infinite streams and unexpected competition between sources may occur. For such cases, other operators like &lt;code&gt;merge&lt;/code&gt; or additional custom handling might better suit your needs.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;blockquote&gt;
&lt;p&gt;The &lt;code&gt;concat&lt;/code&gt; operator is an excellent choice when you need to process streams sequentially and ensure reliable order of execution. Despite its simplicity, it is particularly powerful in scenarios where order and completion are critical. To avoid pitfalls like infinite streams or early termination on errors, always control stream completion and implement proper error handling for a smooth and predictable sequence.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Interesting Aspects&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Optimizing Sequential Data Loading&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
&lt;code&gt;concat&lt;/code&gt; is often used to manage a chain of dependent requests. For example, first obtaining an authorization token and then using it to make API requests.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;concat&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;rxjs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;delay&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;rxjs/operators&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;authToken$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Token received&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&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;fetchData$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Server data loaded&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="nf"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;authToken$&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fetchData$&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&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="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Output:&lt;/span&gt;
&lt;span class="c1"&gt;// Token received&lt;/span&gt;
&lt;span class="c1"&gt;// Server data loaded&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  &lt;strong&gt;Performance&lt;/strong&gt;
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Clear Sequential Efficiency&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
&lt;code&gt;concat&lt;/code&gt; places no extra load on the scheduler as it only manages values from one active stream at any given time.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Delays with Large Streams&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
Performance can decrease if the initial streams contain a large amount of data or take too long to execute, as subsequent Observables must wait for their completion. This is especially important to consider when working with streams in UI components.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;blockquote&gt;
&lt;p&gt;The &lt;code&gt;concat&lt;/code&gt; operator is a powerful tool for sequentially working with streams. It is especially useful if the order of emissions is critically important or if one task must be fully completed before proceeding to the next. However, when using it, it is essential to consider stream completion constraints, proper error handling, and potential delays caused by large or slow streams. Proper use of &lt;code&gt;concat&lt;/code&gt; makes working with sequential data intuitive and manageable.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operator&lt;/th&gt;
&lt;th&gt;Features&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;combineLatest&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Combines the latest values from all streams. Waits for all streams to emit at least one value.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;zip&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Groups values from streams together (one value from each).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;concat&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Processes streams sequentially (one starts only after the previous one completes).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;forkJoin&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Waits for all streams to complete, then returns the results.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;merge&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Processes data in parallel without waiting for stream completion.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Conclusions&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;We’ve covered the foundational operators and succeeded in our first experiments with RxJS. Ahead lie more complex but fascinating challenges where your knowledge of combination operators will become an essential skill. The foundation is already set: we’ve explored how to use &lt;code&gt;zip&lt;/code&gt; and other operators for data synchronization. But knowledge is only half the battle. True understanding comes when you start applying these tools in real-world projects.&lt;/p&gt;

&lt;p&gt;Think about all the complex scenarios where data streams may depend on each other: forms with multiple validations, interactions between API requests, or even time management in games. By understanding how to "orchestrate" streams in RxJS, you won’t just solve problems—you’ll discover entirely new, elegant ways to approach them. And this is just the beginning.&lt;/p&gt;

&lt;p&gt;Every step you take in learning RxJS brings you closer to mastering asynchronous programming. Don’t hesitate to experiment and ask questions. It’s much easier to learn from small examples than to tackle large projects where every stream feels like a mini-puzzle.&lt;/p&gt;

&lt;p&gt;Now it’s time to set new goals, explore different operators, and find what works best for your scenarios. RxJS may seem complex at first, but with every new challenge, it will reveal itself as a powerful tool. Let your journey through stream combination lead you confidently toward true expertise.&lt;/p&gt;

&lt;p&gt;The next step awaits—keep going and continue to unlock the world of reactive programming. Good luck!  &lt;/p&gt;

</description>
      <category>rxjs</category>
    </item>
    <item>
      <title>How to Defeat the Chaos of Manual Backend Contracts: Automating Models in Angular</title>
      <dc:creator>Art Stesh</dc:creator>
      <pubDate>Mon, 14 Apr 2025 14:36:00 +0000</pubDate>
      <link>https://dev.to/artstesh/how-to-defeat-the-chaos-of-manual-backend-contracts-automating-models-in-angular-nh6</link>
      <guid>https://dev.to/artstesh/how-to-defeat-the-chaos-of-manual-backend-contracts-automating-models-in-angular-nh6</guid>
      <description>&lt;p&gt;Greetings,&lt;br&gt;&lt;br&gt;
today I decided to talk about how automatic generation of models and services on the frontend can simplify the development process.&lt;/p&gt;

&lt;p&gt;The problem of interaction between the frontend and backend is one of the biggest headaches for developers. Data format mismatches, outdated documentation, and integration errors inevitably slow down the development process. However, modern approaches make it possible to minimize these challenges.&lt;/p&gt;

&lt;p&gt;One technology that has proven effective for such tasks is &lt;strong&gt;automatic code generation&lt;/strong&gt; from OpenAPI specifications.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Problem with Contracts: Why "Gentlemen’s Agreements" Always Lead to Pain
&lt;/h2&gt;

&lt;p&gt;In the early stages of developing small applications, frontend and backend teams often communicate something like: “Well, let’s agree like normal people! The JSON will look like this, ok?” — “Ok.” It sounds nice, like a promise to meet at the same place in five years.&lt;/p&gt;

&lt;p&gt;A month later — the frontend is already tied to the old contract, while the backend decided to "slightly improve" things, but no one can dispute the original agreements anymore because, of course... they weren’t written down. This leads to a classic scenario:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Backend&lt;/strong&gt;: “Well, you know how we do things in REST, we replaced &lt;code&gt;userId&lt;/code&gt; with &lt;code&gt;clientUuid&lt;/code&gt; and moved personal data into a separate model. It's all logical anyway.”&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Frontend&lt;/strong&gt;: &lt;em&gt;sounds of panic and frustration&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;QA&lt;/strong&gt;: “The backend works perfectly, I’ve logged 100,500 bugs against the frontend team.”&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Manager&lt;/strong&gt;: “My presentation is in two hours; is it really that hard to fix this?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It's at moments like these when you realize: it’s better to spend a couple of hours generating contracts than endlessly "syncing up" with another developer on Slack.&lt;/p&gt;

&lt;p&gt;Here are the main problems teams face:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Inconsistent request and response formats.&lt;/strong&gt; The API is constantly expanding, and the gap between the frontend and backend continues to grow.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unpredictable changes.&lt;/strong&gt; Backend developers add functionality, breaking the frontend — often unintentionally.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lack of up-to-date documentation.&lt;/strong&gt; No one informs the team in time when an endpoint's behavior is modified.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Manual validation.&lt;/strong&gt; Sending requests manually, analyzing errors — all of this wastes an enormous amount of time.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  The Core Idea: Automation Instead of Routine
&lt;/h2&gt;

&lt;p&gt;When the frontend is developed based on a backend with a defined API (e.g., OpenAPI), it's entirely possible to eliminate the manual creation of interfaces, services, and data modeling. Instead, everything is done automatically using code generators.&lt;/p&gt;
&lt;h3&gt;
  
  
  Why Is This Important?
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Data Accuracy&lt;/strong&gt;: Automatic generation of interfaces eliminates the chance of type errors.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Faster Development&lt;/strong&gt;: Instead of creating models manually, developers receive ready-to-use code immediately.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Easier Updates&lt;/strong&gt;: When a backend contract changes, it’s enough to update the OpenAPI specification and regenerate the files — everything on the frontend will update automatically.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  4. &lt;strong&gt;Reduced Developer Workload&lt;/strong&gt;: Teams can focus on functional logic instead of wasting time syncing data.
&lt;/h2&gt;
&lt;h2&gt;
  
  
  How to Implement This in Projects?
&lt;/h2&gt;
&lt;h3&gt;
  
  
  1. Swagger Integration and Documentation Generation
&lt;/h3&gt;

&lt;p&gt;The first key task is to make the API “self-explanatory.” This is important for the frontend (there’s no time to dig into the backend code to figure out how to send a request) and for the testers.&lt;/p&gt;

&lt;p&gt;We set up automatic documentation generation, which is hosted on Swagger UI at the &lt;code&gt;/api-docs&lt;/code&gt; endpoint.&lt;/p&gt;

&lt;p&gt;In C#, connecting it comes down to installing the&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 and

 ```Swashbuckle.AspNetCore.Annotations```

 libraries and adding a few lines of code in Program.cs (or Startup.cs):



```textmate
services.AddSwaggerGen(c =&amp;gt;
        {
            c.SwaggerDoc("v1", new OpenApiInfo { Title = "Api", Version = "v1" });
            var currentAssembly = Assembly.GetExecutingAssembly();
            var xmlDocs = currentAssembly.GetReferencedAssemblies()
                .Union(new[] { currentAssembly.GetName() })
                .Select(a =&amp;gt; Path.Combine(Path.GetDirectoryName(currentAssembly.Location), $"{a.Name}.xml"))
                .Where(f =&amp;gt; File.Exists(f)).ToArray();
            xmlDocs.ToList().ForEach(d =&amp;gt;
            {
                c.IncludeXmlComments(d);
            });
        });
        ...

app.UseSwagger();
app.UseSwaggerUI();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;For other programming languages, integrating Swagger is not a challenge — the vast number of examples available online for practically every use case makes it quick and easy to set up in nearly any tech stack.&lt;/em&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Main Advantages of Swagger:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;A convenient visual interface for exploring endpoints.&lt;/li&gt;
&lt;li&gt;Easy integration into CI/CD for generating up-to-date documentation.&lt;/li&gt;
&lt;li&gt;Enables simple access for all team members (frontend, testers, analysts) to the current state of the API.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  2. Generating Frontend Models with &lt;code&gt;ng-openapi-gen&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Considering that the foundation of our frontend is Angular, for generating models and services based on &lt;code&gt;OpenAPI&lt;/code&gt; schemas, we chose the library &lt;a href="https://github.com/cyclosproject/ng-openapi-gen" rel="noopener noreferrer"&gt;&lt;code&gt;ng-openapi-gen&lt;/code&gt;&lt;/a&gt;. This tool, in a semi-automated manner, creates Angular services and models from the &lt;code&gt;OpenAPI&lt;/code&gt; specification, freeing developers from the need to manually describe data structures and requests.&lt;/p&gt;

&lt;h4&gt;
  
  
  Preparing the OpenAPI Specification
&lt;/h4&gt;

&lt;p&gt;To manage the generation process, a &lt;code&gt;json&lt;/code&gt; file is created (in any location), one for each data source (the application can interact with multiple different APIs):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"$schema"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"../../../../node_modules/ng-openapi-gen/ng-openapi-gen-schema.json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"input"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://localhost:5001/swagger/docs/v1/backend-name"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;backend&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;docs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;URL&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"output"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"src/app/api/backend-name"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;destination&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;generated&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;models&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"ignoreUnusedModels"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"indexFile"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"removeStaleFiles"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"skipJsonSuffix"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"module"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ApiModule"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"configuration"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ApiConfiguration"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h4&gt;
  
  
  Code Generation
&lt;/h4&gt;

&lt;p&gt;Add a new script to&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
:


```json
"openapi-gen-backend-name": "ng-openapi-gen -c &amp;lt;path to the config file from the previous step&amp;gt;/config.json"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it! To generate services and models, simply run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm run openapi-gen-backend-name
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the command is executed, the specified directory (in our case, &lt;code&gt;src/app/api/backend-name&lt;/code&gt;) will contain the automatically generated models, services, and the &lt;code&gt;ApiModule&lt;/code&gt;, which can be integrated into your application.&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="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;NgModule&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;imports&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="nx"&gt;ApiModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forRoot&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;rootUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://localhost:5001&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="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;AppModule&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Using the Models and Services
&lt;/h3&gt;

&lt;p&gt;Generated models and services provide strict typing and a convenient interface for API requests. For example, the &lt;code&gt;User&lt;/code&gt; model and the &lt;code&gt;UserService&lt;/code&gt; service are generated automatically:&lt;/p&gt;

&lt;h5&gt;
  
  
  Example of Generated Models:
&lt;/h5&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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;h5&gt;
  
  
  Example of Generated Service:
&lt;/h5&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="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;providedIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&lt;/span&gt;&lt;span class="dl"&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;UserService&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="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HttpClient&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="nf"&gt;getUsers&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;Observable&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="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="k"&gt;return&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;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&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="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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/users&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, the service can be used in any component of your Angular application:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Often, the code of the generated services may seem odd and not particularly user-friendly, but the idea is that we don’t need to focus on it. All we care about is the contract itself.&lt;/em&gt;&lt;/p&gt;

&lt;h5&gt;
  
  
  Example of Usage:
&lt;/h5&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;Component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;OnInit&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;UserService&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;../api&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="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-list&lt;/span&gt;&lt;span class="dl"&gt;'&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;div *ngFor="let user of users"&amp;gt;
        {{ user.name }} (ID: {{ user.id }})
    &amp;lt;/div&amp;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;UserListComponent&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;OnInit&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;users&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;User&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="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;userService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserService&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="nf"&gt;ngOnInit&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&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="nx"&gt;userService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getUsers&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;data&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&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;h3&gt;
  
  
  Alternatives
&lt;/h3&gt;

&lt;p&gt;It’s worth noting that using OpenAPI is not limited to Angular or frontend development. The approaches outlined here can scale across many popular technologies. For example, in React and TypeScript environments, libraries like &lt;code&gt;openapi-typescript-codegen&lt;/code&gt; and &lt;code&gt;swagger-typescript-api&lt;/code&gt; are widely used to generate strictly typed API clients. In Python and Java ecosystems, tools like &lt;code&gt;openapi-generator&lt;/code&gt; help save development time for both server and client applications, generating code tailored for frameworks such as Flask, Django, Spring Boot, or Kotlin.&lt;/p&gt;

&lt;p&gt;This proves that the main advantage of OpenAPI is its versatility. Regardless of the programming language or framework, OpenAPI unites frontend, backend, and QA teams around a single contract, minimizing human error and integration issues. Whether your team is working with web technologies, mobile platforms, or server applications, OpenAPI and automatic generation tools help standardize processes and accelerate development.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Languages/Frameworks&lt;/th&gt;
&lt;th&gt;Features&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/ferdikoomen/openapi-typescript-codegen" rel="noopener noreferrer"&gt;&lt;code&gt;openapi-typescript-codegen&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;React, TypeScript&lt;/td&gt;
&lt;td&gt;A compact generator for clients with types.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/OpenAPITools/openapi-generator" rel="noopener noreferrer"&gt;&lt;code&gt;openapi-generator&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Vue, Svelte, Python, Java, Kotlin, etc.&lt;/td&gt;
&lt;td&gt;A powerful, multi-platform tool.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/acacode/swagger-typescript-api" rel="noopener noreferrer"&gt;&lt;code&gt;swagger-typescript-api&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;React, Node.js, TypeScript&lt;/td&gt;
&lt;td&gt;Lightweight and fast generator with CLI.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Recommendations for Tool Selection
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;If you are using &lt;strong&gt;Angular&lt;/strong&gt;, your best choice is &lt;code&gt;ng-openapi-gen&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;For &lt;strong&gt;React/TypeScript&lt;/strong&gt;, pick &lt;code&gt;openapi-typescript-codegen&lt;/code&gt; or &lt;code&gt;swagger-typescript-api&lt;/code&gt;. Both libraries work well for different scenarios.&lt;/li&gt;
&lt;li&gt;For complex or multi-language projects, use &lt;strong&gt;&lt;code&gt;openapi-generator&lt;/code&gt;&lt;/strong&gt;, as it supports a broader range of platforms and languages.&lt;/li&gt;
&lt;li&gt;Working with frameworks like &lt;strong&gt;Django&lt;/strong&gt; or &lt;strong&gt;Spring&lt;/strong&gt;? &lt;code&gt;openapi-generator&lt;/code&gt; can even generate server-side code.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  3. Integrating OpenAPI into CI/CD
&lt;/h3&gt;

&lt;p&gt;A major focus should be placed on automating contract validation at the pipeline level to avoid desynchronization between the frontend and backend.&lt;/p&gt;

&lt;h4&gt;
  
  
  What to Add to CI/CD:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Automatic documentation generation (Swagger on the backend) for every deployment.&lt;/li&gt;
&lt;li&gt;Specification validation using tools like &lt;a href="https://github.com/APIDevTools/swagger-cli" rel="noopener noreferrer"&gt;swagger-cli&lt;/a&gt; or &lt;a href="https://github.com/Redocly/openapi-cli" rel="noopener noreferrer"&gt;openapi-cli&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Synchronization of frontend models during the build process (while high-level validations are unlikely here, the mere fact of invalidating the code—and consequently preventing compilation—in case of untracked backend changes significantly reduces reaction time).&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Results: What Did OpenAPI Implementation Achieve?
&lt;/h2&gt;

&lt;p&gt;After several months of active use, we observed the following improvements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Fewer Errors:&lt;/strong&gt; Thanks to strict typing, problems are identified before requests even run.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Faster Development:&lt;/strong&gt; Automating model and documentation generation reduced the time required for updating and integrating APIs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Transparency:&lt;/strong&gt; Swagger UI and generated types simplified API structure comprehension for newcomers to the team.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stable Collaboration:&lt;/strong&gt; QA teams gained access to documentation through Swagger, and frontend developers started working with clear, readable interfaces.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Establishing seamless collaboration between the frontend and backend is no easy task, especially as your project grows and contracts multiply. Automatic generation of frontend models and services helps eliminate routine work, reduce desynchronization risks, and speed up development. Instead of manually writing interfaces or dealing with unverified contracts, you gain a single source of truth, synchronized with just a couple of commands.&lt;/p&gt;

&lt;p&gt;The best part is that you don’t need to completely overhaul your project or development approach. You can start small: set up model and service generation for one module or a key API. Gradually, your process will stabilize, your team will work faster, and the number of bugs at the server-client intersection will noticeably decrease.&lt;/p&gt;

&lt;p&gt;Using tools like OpenAPI or similar solutions only simplifies this process, providing developers with an efficient and convenient way to maintain order in the contract layer. By introducing automation step by step, you’ll not only reduce routine tasks but also make development significantly more comfortable.&lt;/p&gt;

&lt;p&gt;There is an excellent way to confirm this—try it for yourself. And soon, you may find it hard to imagine API development without these kinds of solutions.&lt;/p&gt;

</description>
      <category>swagger</category>
      <category>openapi</category>
    </item>
    <item>
      <title>Code is Written, Not Born: Overcoming the Idea of a "Perfect Project Start"</title>
      <dc:creator>Art Stesh</dc:creator>
      <pubDate>Wed, 09 Apr 2025 13:16:58 +0000</pubDate>
      <link>https://dev.to/artstesh/code-is-written-not-born-overcoming-the-idea-of-a-perfect-project-start-52ln</link>
      <guid>https://dev.to/artstesh/code-is-written-not-born-overcoming-the-idea-of-a-perfect-project-start-52ln</guid>
      <description>&lt;p&gt;Every programmer, regardless of skill level, has faced this situation at least once. You sit down to start a new project, brimming with plans and ideas, full of excitement about creating something perfect. Yet... an hour passes, then two, and all you have on the screen are a few folders, a couple of placeholders, and a &lt;code&gt;README.md&lt;/code&gt; file. Soon enough, you’re returning to the documentation, searching for the "correct" project structure or sneaking peeks at how others did it.&lt;/p&gt;

&lt;p&gt;The same often happens when working in a team: meetings wind up turning into endless discussions about architecture, abstractions, and frameworks. Ideas fly around like comets, everyone agrees everything "should be done the right way," but actual progress? It stagnates. Because the team—along with you—is subconsciously waiting for something: &lt;strong&gt;the perfect start&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The syndrome of the perfect start isn’t just a myth; it’s a genuine roadblock to productive development. In this article, we’ll dive into why waiting for "perfection" means stalling, how this mindset stifles progress, and what you can do about it.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Why Do We Wait for the Perfect Start?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Let’s be honest. The engineering mindset instills in most programmers a desire for "purity" and "eternity." It feels critical that a project is built on a solid foundation that can be scaled and maintained for years. But this relentless pursuit of "flawlessness" often turns into a toxic habit of postponing meaningful action until &lt;strong&gt;"the perfect solution"&lt;/strong&gt; has been found.&lt;/p&gt;

&lt;p&gt;The problem is that perfection is usually unattainable. Here’s why:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The world changes faster than we write code.&lt;/strong&gt; By the time you finish analyzing that new framework or pattern, its next version may have already been released, your environment will shift, and the project requirements might evolve—say, from a web app to mobile.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;We can’t foresee everything.&lt;/strong&gt; At the start of a project, it seems like you need to make a hundred decisions right away: Will it be microservices? Will you use a monorepo? What should the layers of abstraction look like? But this mostly leads to analysis paralysis. While you're deep in thought, actual work slows down.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;We fear "tainting" the codebase.&lt;/strong&gt; That relentless commitment to clean code can hold us back. The idea that the code must be clear, tested, and elegant from the very first line often prevents us from writing anything that looks "less-than-perfect."&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Why Is It Crucial to Stop Waiting for the Perfect Start?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;In programming, as in life, the most important thing is movement. Making small, fast, incremental changes is far more effective than spending days crafting a theoretically perfect structure or ideologically flawless architecture.&lt;/p&gt;

&lt;p&gt;Here are a few reasons why:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Decisions always evolve as the project grows.&lt;/strong&gt; During the planning phase, you won’t even be aware of the real challenges yet. The project defines the architecture—not the other way around.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A working prototype beats abstract concepts.&lt;/strong&gt; In most cases, building something functional, even if it’s far from perfect, is already half the battle. Real code doesn’t just push you forward—it provides feedback.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The process itself is where experience lies.&lt;/strong&gt; Even if the initial code is "messy," &lt;strong&gt;you’ve started something&lt;/strong&gt;. Refactoring (yes, everyone loves that word) is every developer's old friend.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;It’s beneficial for business.&lt;/strong&gt; Remember, money isn’t made from "perfect code." For the client, the product, or the end user, functionality is what matters. Code can always be improved later—time cannot.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;A Story About Chasing the "Perfect Start"&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Years ago, I witnessed firsthand the pitfalls of striving for a "perfect start." The task was to develop an internal-use application: a large dashboard for data analysis, interactive tables, graphs, and integrations with multiple APIs. The project seemed ambitious, but progress at the beginning was quick: we finalized the design system, discussed frameworks, and even built a basic structure within a few days.&lt;/p&gt;

&lt;p&gt;Then things spiraled out of control. The team, weary of maintaining "old" projects and deeply convinced that older projects were inherently bad because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;they were legacy code,&lt;/li&gt;
&lt;li&gt;and business never allowed enough time for proper refactoring, rendering them messy,&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;went all-in on trying to "do things right," modern, and perfect.&lt;/p&gt;

&lt;p&gt;It seemed as though every task required a top-tier solution. For example, all API interactions had to be strictly typed, fully universal, and outfitted with error handlers that adhered to top-tier best practices. We attempted to build a custom API interaction mechanism just in case those APIs ever changed, designed complex role models and intricate access logic, and... what was the result?&lt;/p&gt;

&lt;p&gt;After a month, we had &lt;strong&gt;absolutely nothing useful&lt;/strong&gt;—just a mountain of abstractions, dozens of interfaces, and basic logging. It was like that old meme:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;We had 35 lines of code, 2 loops, 2 try/catch blocks for safety,&lt;br&gt;&lt;br&gt;
4 if/else conditions, and a whole bunch of indents and hacks.&lt;br&gt;&lt;br&gt;
Not that this was anywhere near what was needed.&lt;br&gt;&lt;br&gt;
But once you start writing subpar code, it’s hard to stop.&lt;br&gt;&lt;br&gt;
The only thing we feared was recursion.&lt;br&gt;&lt;br&gt;
There is nothing more confusing than recursion.&lt;br&gt;&lt;br&gt;
I knew sooner or later we would resort to it.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In the end, everything had to be thrown out, and we essentially started over with a simpler approach. We focused on bare essentials: did we need a universal API module right away? No, just simple functions for each service. Did we need a universal data abstraction layer from day one? No. And so on. &lt;strong&gt;Per rectum ad astra,&lt;/strong&gt; as they say in some distant Russian villages.&lt;/p&gt;

&lt;p&gt;We quickly assembled a working prototype that was good enough to show the business. And you know what? Many features we initially wanted to implement simply weren’t needed. If we’d developed them from the start, they would’ve been a complete waste of time.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;The Paradox of the Perfect Start&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The most fascinating thing about the chase for a perfect start is that, in real life, it never comes. Here’s why:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Perfect architecture is born only through practice.&lt;/strong&gt; As long as a project exists only in your head, you don’t fully understand it—there are only hypotheses, untested by reality. Real business requirements or user feedback will shatter your plans.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Frameworks and tools age faster than your development.&lt;/strong&gt; It’s unrealistic to expect that this year’s choices will meaningfully help you a year down the line.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Everything becomes clearer after initial chaos.&lt;/strong&gt; When a project gets off the ground with even a minimum working version, it’s much easier to see what needs to be improved.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;How to Stop Waiting for a Perfect Start&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Taking that first step is daunting. But developers love algorithms, so here are practical recommendations—no theory, only tried-and-true methods.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Break tasks down—into absurd simplicity.&lt;/strong&gt;
When faced with an empty project and the overarching goal to "build something big," that scope can feel paralyzing. The solution is to &lt;strong&gt;break tasks down into bite-sized steps&lt;/strong&gt; until they become glaringly obvious.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
   Instead of "Set up API architecture," start with "Create a basic Express server that outputs &lt;code&gt;Hello World&lt;/code&gt;." Sure, it seems too simple—but within an hour, you’ll have something to build upon.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Don’t make too many decisions at once.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
If you’re starting a new project, don’t insist that it must "immediately" have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a precise directory structure,&lt;/li&gt;
&lt;li&gt;the "perfect" Redux/Signals/Vuex store,&lt;/li&gt;
&lt;li&gt;a custom CI/CD pipeline,&lt;/li&gt;
&lt;li&gt;or 100% test coverage.
Leave these goals for later and focus on minimal, working versions.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Let early stages be messy.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Turn your project development into a sequence of iterations. In reality, &lt;strong&gt;there is no such thing as perfect code at the starting point&lt;/strong&gt; because the project itself exists in a state of uncertainty.&lt;/p&gt;

&lt;p&gt;Stop viewing "messy" code or temporary solutions as problems. What’s important is to keep the following chain in mind at all times:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Write working code.&lt;/li&gt;
&lt;li&gt;Improve something in the existing codebase.&lt;/li&gt;
&lt;li&gt;Repeat.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Refactoring is not scary if you do it regularly.&lt;/p&gt;

&lt;h4&gt;
  
  
  4. &lt;strong&gt;Set Action-Oriented Goals Instead of Result-Oriented Ones&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Instead of telling yourself, "Today I will build a modular backend structure," say, "Today I will create authentication functionality with minimal coupling." This approach helps you focus on the process and feel less discouraged if the results don’t yet seem "grand."&lt;/p&gt;

&lt;h4&gt;
  
  
  5. &lt;strong&gt;Learn to Let Go&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Let go of the illusion that the first solution is always final. It isn’t. Code is meant to be written, not carved in stone. If you choose a strategy and later find it ineffective, there’s nothing stopping you from changing it.&lt;br&gt;&lt;br&gt;
Don’t fear leaving something unfinished. What matters is your ability to keep moving forward. In this industry, those who survive are not the ones striving to build something perfect on the first try, but those who release functioning projects and are &lt;strong&gt;willing to improve them with each update.&lt;/strong&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Refactoring Doesn’t Wait for a Special Moment&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Here’s an important point to highlight—the significance of &lt;strong&gt;continuous refactoring.&lt;/strong&gt; Oftentimes, we mentally separate development from refactoring. We think there’s the stage when "we’re quickly writing code for the MVP," and then the stage where "we go back to clean everything up." However, this approach is fundamentally flawed: the business won’t allocate money for a "refactoring stage" unless the project is already collapsing under its own weight.&lt;/p&gt;

&lt;p&gt;Personally, I no longer think of these as separate activities. Refactoring isn’t a distinct phase of the project; it’s &lt;strong&gt;an ongoing part of the development process.&lt;/strong&gt; It’s something you do every day, with every commit, to leave the code just a little better than it was yesterday.&lt;/p&gt;

&lt;p&gt;Years ago, I worked on a project that was a textbook example of poor development at the start. The codebase was chaotic: tons of "hotfixes," duplication, no tests, and a complete mess in directory structure. The term "architecture" simply didn’t apply—the logic was scattered throughout the project. While the product met basic functionality needs, working with it was so complex that adding any new feature became a nightmare, even for experienced developers.&lt;/p&gt;

&lt;p&gt;The project was already generating some income, but adding features or fixing bugs took 2-3 times longer than the initial estimates. The company faced a choice: either rewrite the project completely (which might take up to a year) or gradually improve it without interrupting business operations.&lt;/p&gt;

&lt;p&gt;The first step was agreeing on a practical approach: &lt;strong&gt;"each commit should leave the code slightly better than it was."&lt;/strong&gt; This didn’t mean rewriting everything all at once. Instead, the plan included the following steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;When adding new functionality, refactor the surrounding code. For example, if a method was added to an outdated class, the class would be tidied up, and the method itself implemented according to best practices.&lt;/li&gt;
&lt;li&gt;Gradually introduce testing. Every new or updated piece of code was covered with tests to reduce the risk of breaking something.&lt;/li&gt;
&lt;li&gt;Create small "on-the-fly" tasks. For instance, if we encountered a complicated, unreadable method, we rarely rewrote it immediately but would create a ticket like "Optimize X."&lt;/li&gt;
&lt;li&gt;Standardize code style. Even things like consistent import order and formatting became important to us.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;After a year of gradual improvement, the project passed an external audit when the company attracted a major client. The auditor noted that although remnants of poorly written legacy code still existed, the current structure and maintainability already met professional standards.&lt;/p&gt;

&lt;p&gt;Most importantly, the business saw the difference—adding new features took &lt;strong&gt;less time&lt;/strong&gt; and cost the company significantly less. As a result, the product grew to a point where it became a noticeable source of profit.&lt;/p&gt;

&lt;p&gt;This experience taught me and the team that gradual improvement is a working strategy. There’s no need to rewrite a project from scratch, as long as there’s discipline and a desire to improve it step by step. The key is &lt;strong&gt;consistency and a commitment to bring order.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;The Perfect Start: Nobody Remembers It, But Everyone Sees the Result&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;When a project is finished—or at least up and running—nobody cares about the chaos of the beginning. Users will use it, clients will sign the contracts, and your team lead may or may not give you a pat on the back—but the project lives, and that's what matters.&lt;/p&gt;

&lt;p&gt;Let’s take a look at how many successful products were built. Facebook started as a local university network. Amazon began as an online bookstore. And the first code for Python, according to its creator Guido van Rossum, &lt;strong&gt;looked far from better than your average student project.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If some of the world’s most successful companies began with functionality that "just worked," then why do we believe that our code has to be perfect from the very first attempt?&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Conclusion&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The perfect start doesn’t exist. Period.&lt;/p&gt;

&lt;p&gt;Code is written; it isn’t born. Code lives through constant iterations. There’s no need to aim for the perfect structure in the first few days of development—it’s an illusion. A developer’s job is not to create a masterpiece at the start but to &lt;strong&gt;move forward&lt;/strong&gt;, improving upon what’s already been built, a little at a time.&lt;/p&gt;

&lt;p&gt;Beautiful code is a myth. Good code is the kind that works. Choose the latter.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;P.S. Some Recommended Reading&lt;/strong&gt;
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;"Continuous Delivery"&lt;/strong&gt; by Jez Humble and David Farley – This one’s older, but its core concepts are timeless.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"Refactoring"&lt;/strong&gt; by Martin Fowler – In case someone still hasn’t read it, it’s a must.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"Release It!"&lt;/strong&gt; by Michael Nygard – Insights into real-world struggles and the challenges waiting for us in actual projects.&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>refactoring</category>
    </item>
    <item>
      <title>The Second Step into the World of RxJS: RxJS Operators — How to Learn and Why They Are Needed</title>
      <dc:creator>Art Stesh</dc:creator>
      <pubDate>Fri, 04 Apr 2025 14:00:00 +0000</pubDate>
      <link>https://dev.to/artstesh/the-second-step-into-the-world-of-rxjs-rxjs-operators-how-to-learn-and-why-they-are-needed-1f22</link>
      <guid>https://dev.to/artstesh/the-second-step-into-the-world-of-rxjs-rxjs-operators-how-to-learn-and-why-they-are-needed-1f22</guid>
      <description>&lt;p&gt;Welcome to the second article on the topic of RxJS! If you've read the first part, chances are you've experimented with &lt;code&gt;from()&lt;/code&gt;, &lt;code&gt;interval()&lt;/code&gt; and got familiar with basic operations — filtering and transforming data. We will build upon this foundation to explore more sophisticated tools, so that RxJS can evolve from simply being "interesting experiments" to becoming a truly powerful tool for your projects.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note that this article, as well as the rest in this series, is aimed exclusively at beginners. No groundbreaking insights, revolutionary findings, or "brilliant" thoughts are expected to be found here for experienced users. The content is based on my understanding of how best to structure the learning process of the given topic.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Why are operators so important?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;RxJS can be compared to a LEGO set: you receive a basic platform (Observable) and a variety of tools (operators) that allow you to create virtually any solution, whether it's asynchronous requests, event management, or user input processing.&lt;/p&gt;

&lt;p&gt;Today's question: &lt;em&gt;there are so many operators! How do we master all of them without getting overwhelmed?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Continuing the logic of the previous article, let's state the following: operators cover the widest range of tasks, but the key to success is starting with &lt;strong&gt;the most commonly used and easy-to-understand tools.&lt;/strong&gt; This will help you quickly grasp their power and integrate them into real-world applications.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;How to choose the order of studying operators?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;In this article, we'll get acquainted with the basic core of operators that you should prioritize in your study plan (once you're familiar with operators like &lt;code&gt;map&lt;/code&gt; and &lt;code&gt;filter&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;I divide the learning process into three main stages:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Basic operators for filtering and transforming data.&lt;/strong&gt; (The easiest to start with: they work "out of the box" and are easy to apply to simple code.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Combination operators.&lt;/strong&gt; (These allow you to merge data sources, select necessary streams, and switch between them.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Subscription management mechanisms.&lt;/strong&gt; (Handling unsubscriptions, error processing, and stream completion management.)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Today, we will continue progressing through the first stage by deepening our knowledge.&lt;/p&gt;

&lt;p&gt;In the previous article, you already learned about &lt;code&gt;filter()&lt;/code&gt; and &lt;code&gt;map()&lt;/code&gt;. Now, let’s introduce a new operator — &lt;code&gt;take()&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;take() — Control the number of data items&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;If your data stream starts becoming too long or you need to limit the number of data items processed, the &lt;code&gt;take()&lt;/code&gt; operator comes in handy. For example, let’s say you only want to process the first three messages:&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;interval&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;rxjs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;take&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;rxjs/operators&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;take&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;//  Specify that we only need the first 3 values&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&amp;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="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="c1"&gt;// Output:&lt;/span&gt;
&lt;span class="c1"&gt;// 0&lt;/span&gt;
&lt;span class="c1"&gt;// 1&lt;/span&gt;
&lt;span class="c1"&gt;// 2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;strong&gt;take()&lt;/strong&gt; operator tells the observable stream: “Thanks, but I only need a few of the initial items.” This is especially useful for infinite streams like &lt;code&gt;interval&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;reduce and scan&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Now it's time to get acquainted with operators that allow you to work with the entire stream of data, rather than individual items. For example, when you need to &lt;strong&gt;transform a stream into a single final value&lt;/strong&gt; or &lt;strong&gt;track the accumulation of data over time&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Let’s dive deeper into the &lt;code&gt;reduce&lt;/code&gt; and &lt;code&gt;scan&lt;/code&gt; operators.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Why are reduce and scan so important?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Both operators are often compared to tools from regular arrays, such as &lt;code&gt;Array.reduce()&lt;/code&gt;. However, instead of processing a fixed array, &lt;code&gt;reduce&lt;/code&gt; and &lt;code&gt;scan&lt;/code&gt; work with data streams that may come in gradually. It’s like someone delivering coins to you one by one, and you’re putting them in a piggy bank:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;reduce&lt;/code&gt;&lt;/strong&gt; works like this: it collects the coins in a piggy bank and only tells you the total amount after the process is complete.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;scan&lt;/code&gt;&lt;/strong&gt; works differently: it informs you of the intermediate totals every time you add a coin.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Essentially, &lt;strong&gt;&lt;code&gt;reduce&lt;/code&gt;&lt;/strong&gt; is perfect for final calculations, while &lt;strong&gt;&lt;code&gt;scan&lt;/code&gt;&lt;/strong&gt; is great for working with real-time data.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;reduce: The Final Value Upon Completion&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Imagine you’re running a charity fundraiser. People send you donations one at a time, and your task is to calculate the total amount collected. Only when the fundraiser ends do you make the final announcement:&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="k"&gt;from&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;rxjs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;reduce&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;rxjs/operators&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;donations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt; &lt;span class="c1"&gt;// A stream of donations&lt;/span&gt;

&lt;span class="nx"&gt;donations&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;acc&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;value&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;// Summing up all the donations&lt;/span&gt;
&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;`Total amount: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;total&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;// Output:&lt;/span&gt;
&lt;span class="c1"&gt;// Total amount: 60&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  How does it work?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;reduce()&lt;/code&gt;&lt;/strong&gt; takes two arguments:

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Accumulator function&lt;/strong&gt; &lt;code&gt;(acc, value)&lt;/code&gt;, which updates the accumulated value.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Initial value&lt;/strong&gt; of the accumulator (in this case, 0).&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;In our example, we take each element from the stream (donation) and add it to the total sum &lt;code&gt;acc&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note: You only get the result after the stream is fully completed. If the stream is infinite (e.g., &lt;code&gt;interval&lt;/code&gt;), &lt;code&gt;reduce&lt;/code&gt; simply won't work.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example: Calculating Orders
&lt;/h3&gt;

&lt;p&gt;Now, let's apply &lt;code&gt;reduce&lt;/code&gt; to a task where we have a list of orders, and we want to calculate the total revenue for a company:&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="k"&gt;from&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;rxjs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;reduce&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;rxjs/operators&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;orders&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;total&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;total&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;250&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;total&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt; &lt;span class="p"&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="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;,&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="nx"&gt;acc&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;total&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;// Summing up revenues&lt;/span&gt;
&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;totalRevenue&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;`Общий доход: $&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;totalRevenue&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;// Output:&lt;/span&gt;
&lt;span class="c1"&gt;// Total amount: $400&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the same approach, you could count the number of elements, find the maximum/minimum, or concatenate text strings.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;scan: Real-Time Tracking&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Now imagine that you don’t want to wait for the final result and instead want to observe intermediate totals right away. For example, you start a timer during a run and want to see each new time update.&lt;/p&gt;

&lt;p&gt;This is where &lt;strong&gt;&lt;code&gt;scan()&lt;/code&gt;&lt;/strong&gt; comes to the rescue:&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="k"&gt;from&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;rxjs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;scan&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;rxjs/operators&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;donations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt; &lt;span class="c1"&gt;// Stream of donations&lt;/span&gt;

&lt;span class="nx"&gt;donations&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nf"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;acc&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;value&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;// Calculate the sum at each step&lt;/span&gt;
&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currentSum&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;`Current sum: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;currentSum&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;// Output:&lt;/span&gt;
&lt;span class="c1"&gt;// Current sum: 10&lt;/span&gt;
&lt;span class="c1"&gt;// Current sum: 30&lt;/span&gt;
&lt;span class="c1"&gt;// Current sum: 60&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The feature of &lt;code&gt;scan&lt;/code&gt;&lt;/strong&gt; is that the result updates at &lt;strong&gt;every step&lt;/strong&gt;, not just at the end.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example with real-time data: Bank Account
&lt;/h3&gt;

&lt;p&gt;Now imagine another example: you deposit and withdraw money from a bank account. The &lt;code&gt;scan&lt;/code&gt; operator is perfect for calculating the balance in real-time:&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="k"&gt;from&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;rxjs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;scan&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;rxjs/operators&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;transactions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;75&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt; &lt;span class="c1"&gt;// Deposits and withdrawals&lt;/span&gt;

&lt;span class="nx"&gt;transactions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nf"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;balance&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;transaction&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;// Calculating balance&lt;/span&gt;
&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currentBalance&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;`Current balance: $&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;currentBalance&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;// Output:&lt;/span&gt;
&lt;span class="c1"&gt;// Current balance: $100&lt;/span&gt;
&lt;span class="c1"&gt;// Current balance: $50&lt;/span&gt;
&lt;span class="c1"&gt;// Current balance: $250&lt;/span&gt;
&lt;span class="c1"&gt;// Current balance: $175&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, each new value updates the current account balance. You see the changes instantly, which is perfect for monitoring.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Comparison: Reduce vs Scan&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;To better understand, let's visually compare how &lt;code&gt;reduce&lt;/code&gt; and &lt;code&gt;scan&lt;/code&gt; work. For example, we process the same data stream &lt;code&gt;[1, 2, 3]&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;reduce&lt;/code&gt;&lt;/strong&gt;: will return only the final result — &lt;code&gt;6&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;scan&lt;/code&gt;&lt;/strong&gt;: will first return &lt;code&gt;1&lt;/code&gt;, then &lt;code&gt;3&lt;/code&gt;, and finally &lt;code&gt;6&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example code:&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="k"&gt;of&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;rxjs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;scan&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;rxjs/operators&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;numbers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;acc&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;value&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="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;`reduce: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;result&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;// reduce: 6&lt;/span&gt;

&lt;span class="nx"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nf"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;acc&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;value&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="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;`scan: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;result&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;// scan: 1, 3, 6&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  &lt;strong&gt;When to use Reduce vs Scan?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Here are some tips for selecting the right operator:&lt;/p&gt;

&lt;h3&gt;
  
  
  Use &lt;code&gt;reduce&lt;/code&gt; when:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You are working with a &lt;strong&gt;finite&lt;/strong&gt; stream (e.g., a data array that ends).&lt;/li&gt;
&lt;li&gt;You are only interested in the &lt;strong&gt;final result&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;You need to calculate the total sum, product, or process all elements of the stream.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Use &lt;code&gt;scan&lt;/code&gt; when:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You want to see data &lt;strong&gt;in real-time&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;The stream may be &lt;strong&gt;infinite&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;You need to track intermediate states: for example, balance calculation, accumulating sums, or monitoring updates.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;What's Next?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;After mastering these two tools, you can start combining them with other operators. For example, try adding filtering before &lt;code&gt;reduce&lt;/code&gt; or see how &lt;code&gt;scan&lt;/code&gt; behaves when combined with &lt;code&gt;map&lt;/code&gt; to transform intermediate states.&lt;/p&gt;

&lt;p&gt;Further steps may include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Using &lt;code&gt;scan&lt;/code&gt; for complex states, such as working with objects.&lt;/li&gt;
&lt;li&gt;Exploring more advanced transformations with &lt;code&gt;reduce&lt;/code&gt; to collect arrays or turn a data stream into more complex structures.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Experiment, challenge yourself with real-world tasks, and try to solve them in different ways — this is the best way to master RxJS.&lt;/p&gt;

&lt;h2&gt;
  
  
  Operators debounceTime and throttleTime
&lt;/h2&gt;

&lt;p&gt;It's time to talk about &lt;strong&gt;event frequency management&lt;/strong&gt;, where the main stars are &lt;code&gt;debounceTime&lt;/code&gt; and &lt;code&gt;throttleTime&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;These operators are extremely useful when dealing with events generated at a high frequency (e.g., mouse clicks or text field inputs). They allow you to manage the number and frequency of these events to prevent resource overloading.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Why are debounceTime and throttleTime important?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Imagine the following scenario: a user is quickly typing into a search box, triggering a server request with each character entered. You don't want to send requests every millisecond, as this would overload the server. Instead, you want to optimize the process by handling only the &lt;strong&gt;latest&lt;/strong&gt; input event after a short delay. This is where the &lt;code&gt;debounceTime&lt;/code&gt; operator comes in.&lt;/p&gt;

&lt;p&gt;In another scenario, you might want to limit event handling frequency, allowing only one event to pass through every few seconds, such as when tracking mouse movement. For this, &lt;code&gt;throttleTime&lt;/code&gt; works perfectly.&lt;/p&gt;

&lt;p&gt;Both operators act as filters for frequent events but handle them differently.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;debounceTime: Wait for a pause between events&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  How does debounceTime work?
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;debounceTime&lt;/code&gt; delays event processing until the &lt;strong&gt;stream has been silent&lt;/strong&gt; for a specified amount of time. If a new event occurs within this time, the timer resets. As a result, &lt;code&gt;debounceTime&lt;/code&gt; always processes the &lt;strong&gt;last event&lt;/strong&gt; in a series.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example: Search with delay
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;At this point, we transition to examples that are more challenging to run in online tools such as PlayCode, mentioned in the first article. You may need to switch to local projects to execute the code.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Let's consider a classic task: a user enters a search query into a text field. To avoid creating a server request for every keystroke, we use &lt;code&gt;debounceTime&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;fromEvent&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;rxjs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;debounceTime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;distinctUntilChanged&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;map&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;rxjs/operators&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;searchInput&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;search&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Create an event stream from the text input field&lt;/span&gt;
&lt;span class="nf"&gt;fromEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;searchInput&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;input&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;// Extract text from the input field&lt;/span&gt;
  &lt;span class="nf"&gt;debounceTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;// Wait 300ms after the last input&lt;/span&gt;
&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;searchTerm&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;`Request: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;searchTerm&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;// Output:&lt;/span&gt;
&lt;span class="c1"&gt;// The user quickly types "RxJ", then pauses on "RxJS".&lt;/span&gt;
&lt;span class="c1"&gt;// The console logs only: "Request: RxJS".&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;How &lt;code&gt;debounceTime&lt;/code&gt; works here:

&lt;ul&gt;
&lt;li&gt;If the user pauses for &lt;strong&gt;at least 300ms&lt;/strong&gt;, the stream passes the last change.&lt;/li&gt;
&lt;li&gt;If the user continues typing, the timer resets.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;This approach is useful for optimizing input processing or other frequent events.&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Example: Auto-save with delay
&lt;/h3&gt;

&lt;p&gt;Now, another example: auto-saving a document. When a user makes changes to the text, saving does not happen instantly but &lt;strong&gt;after a pause&lt;/strong&gt; to avoid too frequent requests:&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;fromEvent&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;rxjs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;debounceTime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;map&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;rxjs/operators&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;textarea&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;editor&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nf"&gt;fromEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;textarea&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;input&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;// Extract text from the editor&lt;/span&gt;
  &lt;span class="nf"&gt;debounceTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Wait 1 second after the last change&lt;/span&gt;
&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;`Saving: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;content&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;// The user writes the text: "Hello, RxJS".&lt;/span&gt;
&lt;span class="c1"&gt;// The save action is triggered only after a 1-second pause.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  &lt;strong&gt;throttleTime: Limiting Event Frequency&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  How does throttleTime work?
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;throttleTime&lt;/code&gt; allows passing events no more frequently than the specified time interval, &lt;strong&gt;ignoring all other events&lt;/strong&gt;. If the stream generates multiple events during the interval, the operator will pass through &lt;strong&gt;only the first one&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example: Tracking mouse position
&lt;/h3&gt;

&lt;p&gt;Suppose you want to track mouse movements but do not want to overload the handler with a huge number of events. Instead, you want to receive the mouse coordinates &lt;strong&gt;once every 500ms&lt;/strong&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;fromEvent&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;rxjs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;throttleTime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;map&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;rxjs/operators&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;fromEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mousemove&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nf"&gt;throttleTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;// Pass only one event every 500ms&lt;/span&gt;
  &lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MouseEvent&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="na"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clientX&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clientY&lt;/span&gt; &lt;span class="p"&gt;}))&lt;/span&gt;
&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;`Mouse coordinates: (&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&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="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&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;// Output:&lt;/span&gt;
&lt;span class="c1"&gt;// Move the mouse quickly across the screen. Coordinates are logged only once every 500ms.```&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;endraw&lt;/span&gt; &lt;span class="o"&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;%&lt;/span&gt; &lt;span class="nx"&gt;raw&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;How &lt;code&gt;throttleTime&lt;/code&gt; works:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It's like starting a "timer" after the first event.&lt;/li&gt;
&lt;li&gt;All subsequent events are ignored until the specified interval of time has passed (in our case, 500ms).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Example: Preventing multiple button clicks
&lt;/h3&gt;

&lt;p&gt;Let's consider a scenario: you have a button that sends a request to the server. To avoid sending multiple requests when the button is clicked repeatedly, we use &lt;code&gt;throttleTime&lt;/code&gt;. This ensures that only one click is processed every 2 seconds:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
typescript
import { fromEvent } from 'rxjs';
import { throttleTime } from 'rxjs/operators';

const button = document.getElementById('submit');

fromEvent(button, 'click').pipe(
  throttleTime(2000) // Allow only one click every 2 seconds
).subscribe(() =&amp;gt; console.log('Request sent!'));

// Output:
// The user quickly clicks the button 5 times in a row.
// Only one request is logged every 2 seconds.


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Comparison: debounceTime vs throttleTime&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Both operators allow you to control the frequency of events, but they do it differently. Here are their key differences:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Feature&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;debounceTime&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;throttleTime&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;How it works&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Passes the event only after a pause.&lt;/td&gt;
&lt;td&gt;Passes the first event in each interval.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Best for&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;When you only care about the &lt;strong&gt;last&lt;/strong&gt; event.&lt;/td&gt;
&lt;td&gt;When you need to limit the frequency of events.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Ignores events&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;All events until the pause ends.&lt;/td&gt;
&lt;td&gt;All events during the interval.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;When to use debounceTime vs throttleTime?&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Use &lt;code&gt;debounceTime&lt;/code&gt; if:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You want to wait for the stream to &lt;strong&gt;go silent&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;You're working with searches, auto-saving, or other scenarios where you care about the &lt;strong&gt;last input&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;You want to reduce the number of requests.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Use &lt;code&gt;throttleTime&lt;/code&gt; if:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You want to &lt;strong&gt;limit the event frequency&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Events occur in real-time (e.g., mouse tracking, scrolling).&lt;/li&gt;
&lt;li&gt;You need to prevent multiple consecutive triggers of the same function within a short time.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;The &lt;code&gt;debounceTime&lt;/code&gt; and &lt;code&gt;throttleTime&lt;/code&gt; operators help efficiently manage streams of frequent events, simplifying the handling of user interactions. With their help, you can avoid unnecessary computations, optimize server requests, and enhance the user experience.&lt;/p&gt;

&lt;p&gt;As always, try using these operators in real-world tasks, experimenting with delay and interval parameters. Practice is the best way to master these useful tools!&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;mergeMap and switchMap&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;These operators are used to process data streams when each element of the original stream needs to be turned into a &lt;strong&gt;new stream&lt;/strong&gt;. In other words, each element triggers an additional process, such as an asynchronous request or data transformation.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;What are mergeMap and switchMap used for?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Imagine you have a data stream (e.g., button clicks, text input, or even a list of numbers), and each element triggers an additional action: sends a request, transforms data, or something else. The challenge is that such actions can spawn &lt;strong&gt;many parallel tasks&lt;/strong&gt;, and managing them manually can be difficult.&lt;/p&gt;

&lt;p&gt;Here’s what &lt;code&gt;mergeMap&lt;/code&gt; and &lt;code&gt;switchMap&lt;/code&gt; do:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;mergeMap&lt;/code&gt;&lt;/strong&gt; starts all actions simultaneously (in parallel) and returns results as they are completed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;switchMap&lt;/code&gt;&lt;/strong&gt; cancels the previous action if a new event occurs, returning results only for the latest.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;mergeMap: Process all actions simultaneously&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  How does mergeMap work?
&lt;/h4&gt;

&lt;p&gt;When using &lt;code&gt;mergeMap&lt;/code&gt;, every event in the stream triggers a new action, and &lt;strong&gt;all launched actions work together&lt;/strong&gt;. It does not cancel old tasks but waits for all of them to complete.&lt;/p&gt;

&lt;h4&gt;
  
  
  Example: Multiple numbers — multiple text streams
&lt;/h4&gt;

&lt;p&gt;&lt;em&gt;Let’s look at an example. Pay close attention, as it’s a bit more complex.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;We create a basic stream of numbers &lt;code&gt;[1, 2]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For each element in this stream, we’ll start a new inner stream that returns a string in the format &lt;code&gt;&amp;lt;base number&amp;gt;-&amp;lt;time in seconds&amp;gt;&lt;/code&gt;. To keep the output manageable, we’ll limit the inner stream to two values.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
typescript
import { from, interval } from 'rxjs';
import { mergeMap, take, map } from 'rxjs/operators';

// Stream of numbers
const numbers = from([1, 2]);

// Apply mergeMap
numbers.pipe(
  mergeMap(num =&amp;gt; 
    interval(1000).pipe(
      take(2), 
      map(i =&amp;gt; `Number ${num}-${i}`) // Convert number to text
    )
  )
).subscribe(result =&amp;gt; console.log(result));

// Output:
// Number 1-0
// Number 2-0
// Number 1-1
// Number 2-1


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Here, each element of the stream &lt;code&gt;[1, 2]&lt;/code&gt; starts its own stream, and as tasks are completed, the composed strings are logged to the console. Notice the output: we don’t wait for one task to finish; both streams work simultaneously.&lt;/li&gt;
&lt;li&gt;While we use a synthetic example here, the scenario is realistic. Just imagine that instead of numbers, we have user &lt;code&gt;IDs&lt;/code&gt;, and for each ID, we want to make an asynchronous request to a remote server.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;switchMap: Processing Only the Latest Action&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  How does switchMap work?
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;switchMap&lt;/code&gt; works &lt;strong&gt;differently&lt;/strong&gt;: it cancels all previous actions if a new event occurs. This is useful when you only need the latest action. For example, if a user is typing in a search bar, old requests become irrelevant when a new input is received.&lt;/p&gt;

&lt;h4&gt;
  
  
  Example: Multiple numbers, but only the latest matters
&lt;/h4&gt;

&lt;p&gt;Let's take a stream of numbers and imagine that we want to update the output only for the &lt;strong&gt;latest number&lt;/strong&gt;. If a new event occurs, the previous one is ignored:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
typescript
import { from, interval } from 'rxjs';
import { switchMap, take, map } from 'rxjs/operators';

// Stream of numbers
const numbers = from([1, 2]);

// Apply switchMap
numbers.pipe(
  switchMap(num =&amp;gt;
    interval(1000).pipe(
      take(2),
      map(i =&amp;gt; `Number ${num}-${i}`)
    )
  )
).subscribe(result =&amp;gt; console.log(result));

// Output:
// Number 2-0
// Number 2-1


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;switchMap&lt;/code&gt; cancels the processing of the first value when the second value arrives later.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Difference Between mergeMap and switchMap&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;While both operators map the source stream to new data streams, they are suited for different use cases:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Feature&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;mergeMap&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;switchMap&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;What it does&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Executes &lt;strong&gt;all actions simultaneously&lt;/strong&gt;.&lt;/td&gt;
&lt;td&gt;Cancels previous actions, keeps only the latest one.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;When to use&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;If you're interested in the results of &lt;strong&gt;all tasks&lt;/strong&gt;.&lt;/td&gt;
&lt;td&gt;If you're interested only in the &lt;strong&gt;latest task&lt;/strong&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Example&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Transforming all events (e.g., multiple clicks).&lt;/td&gt;
&lt;td&gt;Text search, where only the most recent input matters.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;When to use mergeMap vs switchMap?&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Use &lt;code&gt;mergeMap&lt;/code&gt; if:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You want to &lt;strong&gt;process each event individually&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;You need to run multiple parallel asynchronous operations.&lt;/li&gt;
&lt;li&gt;All results are important, regardless of the order or completion time.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example: Handling all mouse clicks or sending multiple requests to a server.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use &lt;code&gt;switchMap&lt;/code&gt; if:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You're only interested in the &lt;strong&gt;latest event&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Results from previous events become irrelevant when a new one arrives.&lt;/li&gt;
&lt;li&gt;You're working with streams that update frequently — for example, a search field or a slider input.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s worth noting that understanding these two operators, in my opinion, is one of the most challenging aspects of RxJS. Simple examples may not fully explain the problems they solve. But as always, the key takeaway is to &lt;strong&gt;experiment&lt;/strong&gt;. These are two essential operators, and while they may seem overly complex or rarely applicable at first, it’s enough to understand their general logic to recognize when they might be useful in real-world tasks.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Next Steps: Combining Knowledge&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Now that you're able to work with the basic operators, it's time to create interesting combinations. Consider this task: every second, a number is generated, but you only want to see even numbers, and you also want to double them:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
typescript
import { interval } from 'rxjs';
import { filter, map, take } from 'rxjs/operators';

interval(1000)
  .pipe(
    filter(value =&amp;gt; value % 2 === 0), // Keep only even values
    map(value =&amp;gt; value * 2),         // Double them
    take(5)                          // Take only the first five values
  )
  .subscribe(value =&amp;gt; console.log(value));

// Output:
// 0
// 4
// 8
// 12
// 16


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Such combinations allow you to use several operators together to process a data stream. Your task here is to break the logic of the operators into steps to avoid confusion.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Conclusion&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Getting into RxJS is a journey that requires time, experiments, and gradual learning. It's best to start small: try out basic operators like &lt;code&gt;map&lt;/code&gt;, &lt;code&gt;filter&lt;/code&gt;, and &lt;code&gt;take&lt;/code&gt;, understanding them through examples. This lays a solid foundation for working with more complex tools. Focus on the operators that helped solve specific problems or felt intuitive. Practice is the key to mastering any technology.&lt;/p&gt;

&lt;p&gt;Don't feel pressured to learn all operators at once. RxJS is a powerful tool that reveals its potential as your experience grows. It’s enough to master a few key operators (as we have done in these articles) and then gradually expand your knowledge as the need arises. The official RxJS documentation is structured well for finding operators, making it the best resource for learning them once you’ve grasped the basics.&lt;/p&gt;

&lt;p&gt;Remember: what matters most is not the number of operators you’ve learned but your comfort in using them and your understanding of data stream logic. Solve real-world problems, experiment with operators, combine them, and create your own small projects. This approach allows you to progress from simple to complex without feeling overwhelmed.&lt;/p&gt;

&lt;p&gt;In the third article, we’ll discuss common mistakes in managing RxJS streams, which often complicate developers' lives. Stay productive — see you in the next step!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Test Data in TypeScript: Challenges, Solutions, and My Experience</title>
      <dc:creator>Art Stesh</dc:creator>
      <pubDate>Sat, 29 Mar 2025 11:01:31 +0000</pubDate>
      <link>https://dev.to/artstesh/test-data-in-typescript-challenges-solutions-and-my-experience-25m3</link>
      <guid>https://dev.to/artstesh/test-data-in-typescript-challenges-solutions-and-my-experience-25m3</guid>
      <description>&lt;p&gt;Testing is an integral part of development, especially when it comes to complex applications. It allows us to ensure code quality and prevent unexpected errors. However, an important question every developer faces sooner or later is: how do you balance between thorough test coverage and the time spent writing them? Even more importantly, how do you avoid getting bogged down by the routine?&lt;/p&gt;

&lt;p&gt;Working with test data is a challenge that can exhaust even the most patient developers. Simple tests with primitive parameters are quick and easy to write. But when your method deals with complex objects with nested structures, the situation becomes significantly more complicated. With each new test, more time is spent preparing the data, reducing readability, and increasing overall workload.&lt;/p&gt;

&lt;p&gt;This story is not about promoting libraries or tools. It’s my personal experience with tackling typical issues related to data generation for TypeScript tests. I want to share the difficulties I’ve faced, how common approaches from other languages didn’t work, the solutions I eventually arrived at, and—hopefully—get some new perspectives on the problem from the community.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Test Data Problem in Unit Testing
&lt;/h2&gt;

&lt;p&gt;Writing a good test isn’t too difficult if the functional code adheres to SOLID principles and isn’t overloaded with logic—the test should also end up being simple and concise. But here’s where everything hits a wall: models.&lt;/p&gt;

&lt;p&gt;As long as we’re dealing with concepts like “method accepts a &lt;code&gt;string&lt;/code&gt;”, “method returns an &lt;code&gt;int&lt;/code&gt;”, everything works smoothly. However, when we move on to working with objects, the issue of supplying data to each required model in every test arises.&lt;/p&gt;

&lt;p&gt;At first glance, generating this data might seem trivial: we simply create objects with the required values. But in practice:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Complexity of entities.&lt;/strong&gt; The more complex the data types in the code (e.g., nested structures or collections with various objects), the harder it becomes to manually generate a valid test dataset.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Quantity.&lt;/strong&gt; There are a lot of tests, so preparing each dataset consumes a massive amount of time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Maintenance.&lt;/strong&gt; During refactoring or changes to type structures, updating the test data manually becomes an additional burdensome task.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Approaches to Generating Test Data
&lt;/h2&gt;

&lt;p&gt;Below, I’ll describe a typical progression for a developer writing tests—perhaps you’ll recognize something from your own project.&lt;/p&gt;

&lt;h3&gt;
  
  
  Carrying Everything With You
&lt;/h3&gt;

&lt;p&gt;The first approach is based on the same primitive principle—if I can define the value of an &lt;code&gt;int&lt;/code&gt; variable directly in the test, why not populate a reference type in the same way?&lt;/p&gt;

&lt;p&gt;For simple objects like a &lt;code&gt;Role&lt;/code&gt; class with fields &lt;code&gt;Id&lt;/code&gt; and &lt;code&gt;Name&lt;/code&gt;, this works, of course. But where there’s a &lt;code&gt;role&lt;/code&gt;, there’s also a &lt;code&gt;user&lt;/code&gt; that this role belongs to. Then there’s &lt;code&gt;UserInRole&lt;/code&gt;, which links these two entities... If there’s a method in the functional code like "retrieve all role names for a user with login X", we’ll need to define not just one but three models.&lt;/p&gt;

&lt;p&gt;The test grows as the model gets more complex. It becomes extremely inconvenient to read—how can you understand which of these details are truly important for the test (e.g., the user's login) and which are not?&lt;/p&gt;

&lt;p&gt;With this approach, we:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ruin readability.&lt;/li&gt;
&lt;li&gt;Forget about brevity.&lt;/li&gt;
&lt;li&gt;Spend a lot of time writing each test.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Special Methods in Test Classes
&lt;/h3&gt;

&lt;p&gt;At some point, someone notices that the &lt;code&gt;X&lt;/code&gt; class contains a lot of duplicate code across its tests. That duplicated code gets extracted into a separate method right there in the &lt;code&gt;X&lt;/code&gt; class.&lt;/p&gt;

&lt;p&gt;Tests become short again. We've stopped violating the principle of not duplicating code—although wait, there’s no such specific prohibition for test code! So, what did this achieve? Can we say we’ve improved the conciseness of the tests? To be fair, yes, the code is now cleaner. That’s a small victory!&lt;/p&gt;

&lt;p&gt;But what about the downsides?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Readability has not only failed to improve—it may have actually become worse. Now, to understand what’s happening in a test, you have to jump back and forth between the test and the factory method.&lt;/li&gt;
&lt;li&gt;Situations often arise where the same object needs to be used across different classes. If we create a fake in class &lt;code&gt;A&lt;/code&gt;, what should we do in class &lt;code&gt;B&lt;/code&gt;? Duplicate it? In a small project, this isn’t immediately noticeable, but once the project grows in scale, you find yourself drowning in problems.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Handwritten "Databases"
&lt;/h3&gt;

&lt;p&gt;Eventually, a “genius” idea may arise: why not hard-code a fake database in static collections, predefine all the needed values and relationships, and use this data in our tests?&lt;/p&gt;

&lt;p&gt;There’s not much sense in dwelling on this approach, because it’s only suitable for small projects with three classes and (ideally) no relationships between them.&lt;/p&gt;

&lt;p&gt;This resolves nothing, and the supposed "central management" of fake data is completely overshadowed by major downsides:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;As the project scales, it becomes nearly impossible to account for and define all the relationships within this system.&lt;/li&gt;
&lt;li&gt;The initializer for this fake context quickly grows into a ridiculously long monster.&lt;/li&gt;
&lt;li&gt;Developers using this approach tend to rely too much on the predefined data in these collections. Since the required value is already defined, they simply remember it and use it when writing tests. That’s it—you can kiss your code readability goodbye.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;On top of that, these collections become untouchable—don’t dare to alter anything, because half the tests will immediately fail!&lt;/p&gt;




&lt;h3&gt;
  
  
  Factories
&lt;/h3&gt;

&lt;p&gt;Eventually, you get tired of writing the same thing in every test, or micromanaging the handwritten “database,” and you decide to switch to object factories. For instance, if there’s a &lt;code&gt;Role&lt;/code&gt; class, the testing project gets a &lt;code&gt;RoleFakeFactory&lt;/code&gt; with methods like &lt;code&gt;Create&lt;/code&gt; or &lt;code&gt;CreateMany&lt;/code&gt;. Yes, you'll need to address some implementation decisions, such as whether these factories should be static, how they get data context, and other similar questions.&lt;/p&gt;

&lt;p&gt;However, these aspects don’t significantly affect the usability of this approach. Again, with a small amount of code, this feels like the right solution, and it really seems to work. For the first couple of weeks, everyone is probably satisfied with the results.&lt;/p&gt;

&lt;p&gt;So, what did we achieve?&lt;/p&gt;

&lt;p&gt;We finally solved the duplication problem, as everything is now in its assigned place. That’s... basically it.&lt;/p&gt;

&lt;p&gt;Downsides?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The code is still difficult to read. Yes, management of fakes is now centralized, but how do we interpret the values of these fields?
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserFactory&lt;/span&gt;
 &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;
       &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;Id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;345&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="nx"&gt;Name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Vasya&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="nx"&gt;Email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mail@test.test&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="nx"&gt;PhoneNumber&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;123456789&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="nx"&gt;EmailConfirmed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="nx"&gt;PhoneNumberConfirmed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&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;h3&gt;
  
  
  &lt;code&gt;EmailConfirmed == true&lt;/code&gt; for a specific test? For most tests? Is it a default value? It’s completely unclear where all these values came from and which ones are meaningful or simply irrelevant.
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Readability remains at the same level as the previous approach.&lt;/li&gt;
&lt;li&gt;The sacredness hasn’t gone away—we’ve just slightly reformatted the "magic" values without really changing the core approach.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Automatic Object Generation
&lt;/h3&gt;

&lt;p&gt;Many programming languages provide built-in ways to generate random objects for the purposes of unit testing. While the specifics of how this generation is implemented may vary, it’s important (in the context of our discussion) to consider the consequences of such automation.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Objects are generated at runtime&lt;/strong&gt; with random values, eliminating the need to guess the purpose of hardcoded variables—anything truly necessary for the test can be explicitly specified.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Class instances are created in a single line.&lt;/strong&gt; Goodbye to factories, special methods, and extra utilities—we gain the ability to generate usable objects anywhere and with any configuration.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What did we achieve with automatic generation?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Code readability&lt;/strong&gt; has significantly improved—we can now truly be proud of it. All necessary data for a test is located &lt;em&gt;within&lt;/em&gt; the test itself.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Conciseness&lt;/strong&gt; is also top-notch—everything written is focused on the specific needs of the test, with no unnecessary data cluttering up the code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance of both test writing and reading&lt;/strong&gt; has improved drastically. Depending on prior approaches, speed gains can be considerable—sometimes even multiple times faster.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Efficiency&lt;/strong&gt; is directly tied to simplicity and convenience, and the easier these aspects are, the greater the developers’ engagement. The more eager developers are to write tests, the higher overall quality of the production code.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I often say that most things have already been invented for us, and programmers shouldn’t reinvent the wheel at every step. However, in the case of TypeScript, this concept falters...&lt;/p&gt;




&lt;h3&gt;
  
  
  Inspiration from C#: AutoFixture
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/AutoFixture/AutoFixture" rel="noopener noreferrer"&gt;AutoFixture&lt;/a&gt; has become a true ally in my C# testing endeavors. This library enables the automatic generation of objects based on their type, minimizing manual effort. AutoFixture works by leveraging &lt;strong&gt;reflection&lt;/strong&gt;—access to type metadata at runtime—which makes it incredibly powerful and convenient.&lt;/p&gt;

&lt;p&gt;After trying AutoFixture, I quickly grew fond of this approach: less repetitive code, more focus on test logic. It worked so seamlessly that when transitioning to TypeScript and Angular, I found myself missing such functionality.&lt;/p&gt;




&lt;h3&gt;
  
  
  TypeScript and the Test Data Problem
&lt;/h3&gt;

&lt;p&gt;TypeScript is a powerful language that has become indispensable for developing complex frontend applications. However, it has an important limitation: all types are erased at compile time. Once the code is transpiled into JavaScript, all type information disappears.&lt;/p&gt;

&lt;p&gt;Thus, what can be easily implemented using reflection in C# becomes unattainable within standard TypeScript code. I spent a long time searching for AutoFixture-like alternatives for TypeScript, but all my efforts were in vain. Either the libraries lacked sufficient functionality, or they required explicit type specifications when generating data—failing to resolve the core problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  TypeScript Transformers as a Solution
&lt;/h2&gt;

&lt;p&gt;During my search, I came across &lt;strong&gt;TypeScript Transformers&lt;/strong&gt;. This is an incredibly powerful yet underutilized tool.&lt;/p&gt;

&lt;p&gt;TypeScript Transformers are plugins that intervene in the process of compiling TypeScript to JavaScript. They allow you to add or modify code "on the fly." Thanks to transformers, it becomes possible to do what regular TypeScript code cannot—pass metadata about types into the final JavaScript.&lt;/p&gt;

&lt;p&gt;Inspired by the idea, I set off to develop my own library for automatic object generation for tests.&lt;/p&gt;

&lt;p&gt;At first, it all looked very promising, but... as with many powerful tools, there was a catch. The main difficulty is using TypeScript Transformers. It’s an incredibly useful technology, but it requires some "hoop-jumping." Since TypeScript Transformers interfere with the compilation process, they need to be manually integrated into a project.&lt;/p&gt;

&lt;p&gt;As a result, simply installing the library via &lt;code&gt;npm install&lt;/code&gt; was out of the question.&lt;br&gt;&lt;br&gt;
To work properly with transformations, you need to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use a &lt;strong&gt;build tool&lt;/strong&gt; that supports TypeScript Transformers (such as Webpack with &lt;code&gt;ts-loader&lt;/code&gt;, or other tools like &lt;code&gt;esbuild&lt;/code&gt; or &lt;code&gt;ts-patch&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Register the transformer in the compiler configuration—not just declare it but add a new phase to the project build process.&lt;/li&gt;
&lt;li&gt;Occasionally update the settings when TypeScript gets updated. Unfortunately, updates are not always seamless.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Although these steps may not sound overly complex, in practice, not every developer is willing to dive into build configuration just to use a single library. Over time, I was able to streamline everything into &lt;a href="https://forger.artstesh.ru/f12a8054-450e-46c0-9d9d-bbfc9e9b71d2" rel="noopener noreferrer"&gt;simple steps&lt;/a&gt;, but "interesting" approaches almost always lead to increased bugs and difficulties for users. Still, this is where I am currently—it’s the best solution I’ve come up with so far. The dependencies on the tooling remain an issue—not all build tools handle transformations effectively. For example, Webpack with &lt;code&gt;ts-loader&lt;/code&gt; and &lt;code&gt;tsc&lt;/code&gt; work fine, but lighter tools like Vite or esbuild may require an abundance of effort to configure.&lt;/p&gt;

&lt;p&gt;In simpler terms, I couldn’t make my library "just work out of the box," which doesn’t personally bother me. In my standard Angular projects, everything works fine, as it does in rare "pure" TypeScript setups with Jest. But beyond that—there’s a fog of war I haven’t had time to penetrate.&lt;/p&gt;


&lt;h3&gt;
  
  
  Is It Worth It?
&lt;/h3&gt;

&lt;p&gt;Given all the downsides of working with transformers, you might ask: is this even worth it? After all, data generation can still be set up manually, or you could rely on a simpler API.&lt;/p&gt;

&lt;p&gt;For me, the answer is clear: all this "hoop-jumping" is absolutely worth the effort. I believe the time I spent digging through TS documentation and writing/testing the library was justified, and as for its usage? I now include it in all my projects by default.&lt;/p&gt;

&lt;p&gt;Moreover, the transformer technology itself is still evolving. Over time, the TypeScript build ecosystem may make the connection process simpler than it is now.&lt;/p&gt;


&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;In the end, I arrived at a form of testing that closely resembles the logic I used to write in C#.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;br&gt;
it('number of lines is correct', () =&amp;gt; {&lt;br&gt;
  const items = Forger.create()!;&lt;br&gt;
  //&lt;br&gt;
  const result = service.convert(items);&lt;br&gt;
  //&lt;br&gt;
  should().array(result).length(items.length);&lt;br&gt;
});&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


`ListItem` here is a complex object with numerous fields, but since its content isn’t relevant within the context of the test, it’s enough to populate it with any values just to ensure the tested code works correctly, allowing the narrow logic of the test to be evaluated.

The library is actively used in my projects, and I hope it becomes a convenient tool for other developers looking to make their tests not only high-quality but also easier to write. Perhaps someone will even suggest new approaches and methods. You can explore its capabilities [here](https://forger.artstesh.ru/76a7eb56-cc26-481c-9302-cf8ddbd2002a), and feel free to share suggestions in the comments or via direct messages—I’d be happy to hear constructive ideas.  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>typescript</category>
      <category>fixture</category>
      <category>testing</category>
    </item>
    <item>
      <title>Getting Rid of Boilerplate in Angular: Using TypeScript Decorators</title>
      <dc:creator>Art Stesh</dc:creator>
      <pubDate>Tue, 25 Mar 2025 14:00:00 +0000</pubDate>
      <link>https://dev.to/artstesh/getting-rid-of-boilerplate-in-angular-using-typescript-decorators-3fdj</link>
      <guid>https://dev.to/artstesh/getting-rid-of-boilerplate-in-angular-using-typescript-decorators-3fdj</guid>
      <description>&lt;p&gt;Every Angular developer has wondered at least once: &lt;strong&gt;"Why am I writing so much repetitive code?"&lt;/strong&gt; Dependency injection, recurring logging methods, uniform event handling—all of it feels like an endless battle with boilerplate code. However, Angular has a powerful feature in its arsenal to simplify tasks and automate repetitive actions—&lt;strong&gt;TypeScript Decorators&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Decorators are a quick way to add unified functionality to your codebase, making it cleaner, more understandable, and easier to maintain. In this article, we'll explore how decorators can help eliminate repetitive patterns while introducing &lt;strong&gt;flexibility&lt;/strong&gt; and &lt;strong&gt;error reduction&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction to TypeScript Decorators
&lt;/h2&gt;

&lt;p&gt;Decorators are functions applied to classes, methods, properties, or parameters. They allow you to modify the behavior of an object or its elements without altering its original source code. Decorators are available in TypeScript thanks to the ES7 standard. In fact, Angular heavily relies on them: &lt;code&gt;@Component&lt;/code&gt;, &lt;code&gt;@Injectable&lt;/code&gt;, &lt;code&gt;@Input&lt;/code&gt;, etc.&lt;/p&gt;

&lt;h3&gt;
  
  
  Purpose of Decorators
&lt;/h3&gt;

&lt;p&gt;The main goal of decorators is to &lt;strong&gt;add new behavior to objects&lt;/strong&gt;. They eliminate boilerplate code, ensure &lt;strong&gt;reusability of functionality&lt;/strong&gt;, and make the code more readable. Decorators allow you to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Modify or extend the functionality&lt;/strong&gt; of classes, properties, methods, and parameters.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automate everyday tasks&lt;/strong&gt;, such as:

&lt;ul&gt;
&lt;li&gt;Logging,&lt;/li&gt;
&lt;li&gt;Validation,&lt;/li&gt;
&lt;li&gt;Caching,&lt;/li&gt;
&lt;li&gt;Dependency injection (DI).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add metadata&lt;/strong&gt;, like class or method registration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simplify API interaction&lt;/strong&gt;, freeing developers from manual calls.&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Example problem:&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Suppose you want to log every method call in the application. Instead of adding &lt;code&gt;console.log()&lt;/code&gt; into each method, you can use method decorators:&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;function&lt;/span&gt; &lt;span class="nf"&gt;LogMethod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;propertyKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;descriptor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PropertyDescriptor&lt;/span&gt;&lt;span class="p"&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;originalMethod&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;descriptor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nx"&gt;descriptor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&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;`Method invoked: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;propertyKey&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, arguments: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&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;return&lt;/span&gt; &lt;span class="nx"&gt;originalMethod&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;apply&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="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&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;descriptor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Example&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;LogMethod&lt;/span&gt;
  &lt;span class="nf"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;param&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Doing something important...&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="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Example&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;test&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Console:&lt;/span&gt;
&lt;span class="c1"&gt;// Method invoked: doSomething, arguments: ["test"]&lt;/span&gt;
&lt;span class="c1"&gt;// Doing something important...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  How Do Decorators Work?
&lt;/h2&gt;

&lt;p&gt;Decorators are &lt;strong&gt;functions&lt;/strong&gt; that run at runtime. They are called to add or modify the functionality of a class, its methods, properties, or parameters.&lt;/p&gt;

&lt;h3&gt;
  
  
  Types of Decorators:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Class Decorators&lt;/strong&gt;: Operate on the class itself.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Property Decorators&lt;/strong&gt;: Modify properties or fields of the class.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Method Decorators&lt;/strong&gt;: Allow modification of a method’s behavior.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Parameter Decorators&lt;/strong&gt;: Process method or constructor parameters.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Example Tasks &amp;amp; Implementations
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Task 1: Method Call Logging (Method Decorator)&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Tracking user interactions and actions in an application is a common requirement. Instead of manually adding logger calls in every method, you can automate logging using method decorators.&lt;/p&gt;

&lt;h4&gt;
  
  
  Implementation:
&lt;/h4&gt;

&lt;p&gt;We create a &lt;code&gt;@LogMethod&lt;/code&gt; decorator to log method names and passed arguments:&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;function&lt;/span&gt; &lt;span class="nf"&gt;LogMethod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;propertyKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;descriptor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PropertyDescriptor&lt;/span&gt;&lt;span class="p"&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;original&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;descriptor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nx"&gt;descriptor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&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;`Method invoked: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;propertyKey&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; with arguments: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;original&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;apply&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="nx"&gt;args&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;`Method &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;propertyKey&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; returned: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&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;return&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&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;descriptor&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;h4&gt;
  
  
  &lt;strong&gt;Usage&lt;/strong&gt;:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Calculator&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;LogMethod&lt;/span&gt;
  &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;number&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;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;b&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;calc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Calculator&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;calc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&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="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Console output&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Method invoked: add with arguments: [5,7]
Method add returned: 12
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  &lt;strong&gt;Task 2: Transformations and Validations (Property Decorator)&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;In form-based applications, user input often requires automatic transformations and validations. By using property decorators, you can easily add such functionality without overriding &lt;code&gt;set&lt;/code&gt; methods explicitly.&lt;/p&gt;

&lt;h4&gt;
  
  
  Automatic Transformation with &lt;code&gt;@Capitalize&lt;/code&gt;:
&lt;/h4&gt;

&lt;p&gt;This decorator ensures string inputs are capitalized:&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;function&lt;/span&gt; &lt;span class="nf"&gt;Capitalize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;propertyKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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;getter&lt;/span&gt; &lt;span class="o"&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="nx"&gt;value&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;setter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;newValue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;charAt&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="nf"&gt;toUpperCase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;newValue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;defineProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;propertyKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;getter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;setter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;enumerable&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;configurable&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;strong&gt;Usage&lt;/strong&gt;:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Capitalize&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&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="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;name&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;john&lt;/span&gt;&lt;span class="dl"&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="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// "John"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Input Validation:
&lt;/h4&gt;

&lt;p&gt;Automatically validate inputs with a decorator:&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;function&lt;/span&gt; &lt;span class="nf"&gt;ValidatePositive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;propertyKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&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;getter&lt;/span&gt; &lt;span class="o"&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="nx"&gt;value&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;setter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newValue&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Property &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;propertyKey&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; must be positive`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;newValue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;defineProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;propertyKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;getter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;setter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;enumerable&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;configurable&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;strong&gt;Usage&lt;/strong&gt;:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Product&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;ValidatePositive&lt;/span&gt;
  &lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&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="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&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="nx"&gt;price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;price&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Error: "Property price must be positive"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  &lt;strong&gt;Task 3: Automating DI in Services (Class Decorator)&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Centralize recurring logic for requests, caching, or error handling in Angular services with decorators. Here's an example of a caching decorator &lt;code&gt;@Cacheable&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;methodCache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Cacheable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;propertyKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;descriptor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PropertyDescriptor&lt;/span&gt;&lt;span class="p"&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;original&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;descriptor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nx"&gt;descriptor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&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;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;methodCache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&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;`Using cache for: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;propertyKey&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="nx"&gt;key&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;return&lt;/span&gt; &lt;span class="nx"&gt;methodCache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&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;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;original&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;apply&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="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;methodCache&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="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&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;result&lt;/span&gt;&lt;span class="p"&gt;;&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;descriptor&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;h4&gt;
  
  
  &lt;strong&gt;Usage&lt;/strong&gt;:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ApiService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Cacheable&lt;/span&gt;
  &lt;span class="nf"&gt;fetchData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&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;`Fetching data from &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;url&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;return&lt;/span&gt; &lt;span class="s2"&gt;`Data from &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;url&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="p"&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;api&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ApiService&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="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetchData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://example.com/api&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// "Fetching data..."&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="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetchData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://example.com/api&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// "Using cache..."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  &lt;strong&gt;Task 4: Improve Angular Components with Decorators&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Automate subscriptions in components with &lt;code&gt;@Autounsubscribe&lt;/code&gt; to avoid memory leaks.&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;function&lt;/span&gt; &lt;span class="nf"&gt;AutoUnsubscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Function&lt;/span&gt;&lt;span class="p"&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;originalOnDestroy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ngOnDestroy&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ngOnDestroy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for &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;prop&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &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="nx"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;typeof&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;prop&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;unsubscribe&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;function&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;unsubscribe&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;originalOnDestroy&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;originalOnDestroy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;apply&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="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;h4&gt;
  
  
  &lt;strong&gt;Usage&lt;/strong&gt;:
&lt;/h4&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;AutoUnsubscribe&lt;/span&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-example&lt;/span&gt;&lt;span class="dl"&gt;'&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="dl"&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;ExampleComponent&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;OnDestroy&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;subscription&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;someService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&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="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;someService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;SomeService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

  &lt;span class="nf"&gt;ngOnDestroy&lt;/span&gt;&lt;span class="p"&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Component destroyed&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Downsides of Decorators and When to Avoid Using Them
&lt;/h2&gt;

&lt;p&gt;While powerful and convenient, decorators are not without drawbacks. There are scenarios where their usage can lead to problems, increased code complexity, or degraded performance.&lt;/p&gt;




&lt;h3&gt;
  
  
  1. &lt;strong&gt;Unstable Standardization&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;The Problem:&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Decorators are still at &lt;strong&gt;Stage 2&lt;/strong&gt; in the ECMAScript specification. This means their behavior may change, and their implementation could differ in future versions of JavaScript. As a result, the code written with decorators today might require rewriting in the future.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Consequences:&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Complete reliance on the TypeScript implementation of decorators.&lt;/li&gt;
&lt;li&gt;Not all JavaScript-compatible tools and libraries support them (e.g., some specific libraries or execution environments).&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  2. &lt;strong&gt;Reduced Readability of Complex Code&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;The Problem:&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Decorators abstract functionality, hiding it behind a concise syntax. As a result, if you use multiple decorators in a single class or component, the program's behavior becomes less predictable—especially for developers unfamiliar with advanced decorators in your project.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Example:&lt;/strong&gt;
&lt;/h4&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;Auth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;admin&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="nd"&gt;TrackUsage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;createUser&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="nd"&gt;Retry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;createUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Implementation&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;For a developer encountering this code, it will be unclear:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What each decorator does.&lt;/li&gt;
&lt;li&gt;How they interact with each other.&lt;/li&gt;
&lt;li&gt;At what stage of execution each decorator is applied.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;When This Becomes Critical:&lt;/strong&gt;
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;In projects with a large number of contributors, where code simplicity is paramount.&lt;/li&gt;
&lt;li&gt;For newcomers to the project, who may spend extra time understanding the logic.&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  3. &lt;strong&gt;Excessive Magic (Overhead)&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;The Problem:&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Decorators often introduce additional "magical" functionality, leading to unexpected effects. For example, changes via &lt;code&gt;Object.defineProperty&lt;/code&gt; or method rewriting can make debugging and understanding the code more challenging.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Consequences:&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Difficult debugging:&lt;/strong&gt; The program's behavior may depend on the sequence in which the decorators are applied.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unpredictable bugs:&lt;/strong&gt; Migrating to a new version of TypeScript or Angular could break the functionality of decorators.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  4. &lt;strong&gt;Challenges in Testing&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;The Problem:&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Testing tools may struggle to interpret code with excessive hidden logic in decorators. Decorators may introduce proxy layers or change the "underlying" code, making test simulation more complex.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Example:&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;If you use validation decorators (e.g., &lt;code&gt;@Validate&lt;/code&gt;), tests may require direct access to the internal implementation of the decorator, making the test-writing process less straightforward.&lt;/p&gt;




&lt;h3&gt;
  
  
  5. &lt;strong&gt;Debugging Complexity&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;The Problem:&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;When decorators not only add metadata but also modify methods/properties, the results can become harder to anticipate. Debugging tools (like debuggers) sometimes display the "unmodified" code, rather than its actual behavior.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Example:&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;While using a debugger to view a modified method, it might not be immediately clear where and how the decorator has been applied.&lt;/p&gt;




&lt;h3&gt;
  
  
  When Should You Avoid Using Decorators?
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. &lt;strong&gt;Small Projects&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;In small applications with minimal repetition, decorators are unlikely to justify their added complexity. Additional abstraction will only make the code harder to read, while simplifying minimal logic won’t yield significant benefits.&lt;/p&gt;

&lt;h4&gt;
  
  
  2. &lt;strong&gt;Projects with a Low Learning Curve&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;If your project is aimed at junior developers or those unfamiliar with TypeScript decorators, their use could become a barrier. For such teams, it's better to avoid overcomplicating code.&lt;/p&gt;

&lt;h4&gt;
  
  
  3. &lt;strong&gt;Risky Modifications to State&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;If a decorator modifies an existing method/property, it might cause unstable behavior—especially if decorators are layered on top of each other.&lt;/p&gt;




&lt;h3&gt;
  
  
  Best Practices for Using Decorators
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Use Decorators for Repetitive, "Boring" Logic:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Decorators work best for tasks like logging, authorization, and caching—situations where reducing boilerplate is important.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Avoid Overcomplicating Code with Abstractions:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
If a task can be accomplished with two lines of code without a decorator, it’s better to avoid them.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Document Decorator Behavior:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Always explain what a decorator does in comments or documentation to avoid confusion.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Monitor Performance:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
If a decorator performs resource-intensive tasks, ensure it doesn’t noticeably impact application performance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Don’t Add Business Logic to Decorators:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Decorators should remain lightweight, addressing infrastructure concerns such as logging or validation, not directly processing business data.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Decorators in TypeScript are a powerful tool, but like any tool, they require a reasonable approach. Overusing them, particularly in simple projects, will only complicate the code and make your work harder. It’s important to understand that decorators are best suited for managing &lt;strong&gt;cross-cutting concerns&lt;/strong&gt; (e.g., logging, authorization, validation), but not everything.&lt;/p&gt;

&lt;p&gt;Remember: &lt;strong&gt;The simpler and clearer the code, the better for you and your team.&lt;/strong&gt; Decorators are a tool—not a magical solution to all problems! 😊&lt;/p&gt;

</description>
      <category>angular</category>
      <category>decorators</category>
      <category>typescript</category>
    </item>
    <item>
      <title>The First Step into the World of RxJS: Getting to Know Observables</title>
      <dc:creator>Art Stesh</dc:creator>
      <pubDate>Thu, 20 Mar 2025 14:00:00 +0000</pubDate>
      <link>https://dev.to/artstesh/the-first-step-into-the-world-of-rxjs-getting-to-know-observables-12jo</link>
      <guid>https://dev.to/artstesh/the-first-step-into-the-world-of-rxjs-getting-to-know-observables-12jo</guid>
      <description>&lt;p&gt;Learning something new is always a challenge, especially when you're deluged with streams of terms, functions, and concepts that aren't immediately obvious. Let's dive into some simple examples and try to create a mini-plan for mastering this topic. I’m even considering writing a series of articles in this vein, inspired by my experience interacting with newcomers to the field (as long as the topic and presentation spark interest).&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Why Learn RxJS at All?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Reactive programming is becoming an increasingly popular approach in modern application development, especially where asynchronous data is critical—user input, working with WebSockets, event handling, or API requests. RxJS is widely used in frameworks like &lt;strong&gt;Angular&lt;/strong&gt;, where its knowledge is practically essential for working with components, services, and data streams.&lt;/p&gt;

&lt;p&gt;But even beyond specific framework requirements, RxJS is a powerful tool that simplifies and enhances how we handle asynchronous operations compared to traditional callback or promise approaches. Mastering it will not only give you an edge in managing complex applications but also provide a new perspective on managing data and events.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;The Problem With Getting Started&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The problem many beginners face when first encountering the topic of subscriptions lies in the abundance of topics and nuances related to it. Tons of articles, discussions, and documentation on topics like &lt;em&gt;"RxJS mergeMap vs switchMap vs concatMap vs exhaustMap"&lt;/em&gt; can cause a headache in just the first fifteen minutes. That’s why my first piece of advice is this: limit the list of topics and tools you’re trying to master to the bare minimum. Decomposition is always important — you need to "eat the elephant piece by piece." Similar to how a chess beginner learns, they first study each piece individually, memorize its capabilities and nuances, and gradually move on to the overarching strategy of the game. So, let’s sweep all the pieces off the board and leave only the pawn.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Imagine Yourself as a Magazine Subscriber&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The core idea of Observables is &lt;strong&gt;observing events and responding to them&lt;/strong&gt;. To clarify, let’s compare Observables with a magazine subscription system:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Publisher (Data Source)&lt;/strong&gt; sends data.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;subscriber&lt;/strong&gt; wants to get updates regularly (data).&lt;/li&gt;
&lt;li&gt;The subscriber agrees and &lt;strong&gt;subscribes&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;While the subscription is active, updates (data) are received.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Key Observations:&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Subscribed data only starts flowing after the subscription.&lt;/li&gt;
&lt;li&gt;You can unsubscribe to stop receiving data.&lt;/li&gt;
&lt;li&gt;Sometimes the publisher stops sending updates entirely.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In programming terms:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;There’s a &lt;strong&gt;data source&lt;/strong&gt; (e.g., an event stream or HTTP response).&lt;/li&gt;
&lt;li&gt;Subscribers (&lt;strong&gt;you&lt;/strong&gt;) monitor changes.&lt;/li&gt;
&lt;li&gt;You "subscribe" using &lt;code&gt;subscribe()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;While subscribed, you continuously get updates.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Diving into Observable Code Basics&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Traditional Observable Example&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;An Observable is an object that produces data or notifications. The data can be of any type: numbers, strings, arrays, results of HTTP requests. And here’s where the interesting part begins: traditionally, at this point, it’s common to show examples like:&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;Observable&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;rxjs&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;observable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&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;subscriber&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;subscriber&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;subscriber&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;subscriber&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;subscriber&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;complete&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;observable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;next&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&amp;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="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;complete&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="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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Stream completed&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="c1"&gt;// Console output:&lt;/span&gt;
&lt;span class="c1"&gt;// 1&lt;/span&gt;
&lt;span class="c1"&gt;// 2&lt;/span&gt;
&lt;span class="c1"&gt;// 3&lt;/span&gt;
&lt;span class="c1"&gt;// Stream completed&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But in my experience, this approach doesn’t work at all with beginners – too many things happen all at once, which either require lengthy line-by-line explanations or forcing them to “look the other way” and focus only on the “main idea” while ignoring the “other non-essential details.” But we agreed to try and find the smallest possible topic, so I propose starting with the &lt;code&gt;from()&lt;/code&gt; operator and building the learning process around it. Why? Simply because it “sweeps away” all the questions related to creating streams, emitting events, completing subscriptions, and so on.&lt;/p&gt;

&lt;p&gt;Going back to the newspaper example: for now, we just want to figure out how to get our favorite newspaper delivered every day, not how to build a printing press and set up its operations.&lt;/p&gt;

&lt;p&gt;So, let’s agree that for our basic experiments, we’ll only need two things: the &lt;code&gt;from&lt;/code&gt; operator and some collection of objects that we’ll come up with as we go.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Where to Run the Code?&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;If you're comfortable setting up a local app for experimenting, do so.&lt;/li&gt;
&lt;li&gt;Otherwise, consider online tools like &lt;a href="https://playcode.io/typescript" rel="noopener noreferrer"&gt;PlayCode&lt;/a&gt;—quick and easy with RxJS support.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Creating a Basic Number Stream&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Let’s simplify the earlier example using &lt;code&gt;from()&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;from&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;rxjs&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;obs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="nx"&gt;obs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&amp;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="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="c1"&gt;// Console output:&lt;/span&gt;
&lt;span class="c1"&gt;// 1&lt;/span&gt;
&lt;span class="c1"&gt;// 2&lt;/span&gt;
&lt;span class="c1"&gt;// 3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s the entire basic example, though it’s worth dedicating enough time to it. The printing press analogy isn’t very fitting here due to the simplicity of what’s happening, so let’s switch to people instead. Sometimes in conversations, we touch on a topic that’s really interesting to the other person, and they start pouring out their knowledge/opinions on the subject (it could be office gossip about colleagues, or it could be the lore of Warhammer – luck plays a role here). That’s exactly how &lt;code&gt;obs&lt;/code&gt; holds its “knowledge” about the numbers 1, 2, 3, so it can dump them on anyone who subscribes. When we subscribe to &lt;code&gt;obs&lt;/code&gt;, we &lt;em&gt;sequentially&lt;/em&gt; receive the entire collection of elements. Moreover, if another listener connects to &lt;code&gt;obs&lt;/code&gt;, they will again receive the entire collection from the beginning – just like in real life, you just can’t get this guy to stop talking!&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Example (Multiple Subscriptions):&lt;/strong&gt;
&lt;/h4&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="k"&gt;from&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;rxjs&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;obs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="nx"&gt;obs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&amp;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="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// First subscriber&lt;/span&gt;
&lt;span class="nx"&gt;obs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&amp;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="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// Second subscriber&lt;/span&gt;
&lt;span class="c1"&gt;// Console output:&lt;/span&gt;
&lt;span class="c1"&gt;// 1&lt;/span&gt;
&lt;span class="c1"&gt;// 2&lt;/span&gt;
&lt;span class="c1"&gt;// 3&lt;/span&gt;
&lt;span class="c1"&gt;// 1&lt;/span&gt;
&lt;span class="c1"&gt;// 2&lt;/span&gt;
&lt;span class="c1"&gt;// 3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If a second subscriber connects, the data replays from the first item.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;What’s Next?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Next, start experimenting with this micro-code, gradually expanding its functionality. Change the data and their types; work, for example, with a collection of strings or objects. Get used to the idea that all these subscriptions are just a versatile tool that works according to a pattern, not some highly complex space shuttle.&lt;/p&gt;

&lt;p&gt;Next, it's worth exploring the logic of &lt;code&gt;pipe()&lt;/code&gt; with two operators: &lt;code&gt;map()&lt;/code&gt; and &lt;code&gt;filter()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;As for &lt;code&gt;pipe()&lt;/code&gt; itself, there’s no need to dwell on it too much—it’s simply a function that allows us to modify the data stream by applying the corresponding operators (we’ll start with the two mentioned).&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Operators: &lt;code&gt;filter&lt;/code&gt; and &lt;code&gt;map&lt;/code&gt;&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;&lt;code&gt;filter&lt;/code&gt; – Set Conditions for Data&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;That guy with the gossip is unlikely to share gossip about you directly with you; he’ll save those stories for another conversation partner. And there you have the idea of filtering: we won’t always work with the full data stream—sometimes, we need to filter out irrelevant data.&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="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;filter&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;rxjs&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;obs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;pipe&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;n&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="nx"&gt;obs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&amp;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="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="c1"&gt;// Console output:&lt;/span&gt;
&lt;span class="c1"&gt;// 3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;filter&lt;/code&gt; sets a condition for publishing data, and once again, the same suggestion: experiment, change data types and conditions, get fully comfortable with the ideas of filtering so that you approach other operators later with more awareness and understanding.&lt;/p&gt;

&lt;p&gt;It's worth noting an important detail here: &lt;code&gt;pipe&lt;/code&gt; can be applied to the entire subscription as a whole or to a specific subscriber only.&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="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;filter&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;rxjs&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;obs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;pipe&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;n&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="nx"&gt;obs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&amp;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="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="nx"&gt;obs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&amp;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="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="c1"&gt;// Console output:&lt;/span&gt;
&lt;span class="c1"&gt;// 3&lt;/span&gt;
&lt;span class="c1"&gt;// 3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, the source itself filters the data, and none of the subscribers can get the unfiltered set—our “gossiper” is not willing to share everything they know.&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="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;filter&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;rxjs&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;obs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="nx"&gt;obs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&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;n&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&amp;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="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="nx"&gt;obs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&amp;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="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="c1"&gt;// Console output:&lt;/span&gt;
&lt;span class="c1"&gt;// 3&lt;/span&gt;
&lt;span class="c1"&gt;// 1&lt;/span&gt;
&lt;span class="c1"&gt;// 2&lt;/span&gt;
&lt;span class="c1"&gt;// 3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, one of the listeners doesn’t want to know anything about numbers less than two, while &lt;code&gt;obs&lt;/code&gt; faithfully provides the entire set.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;&lt;code&gt;map&lt;/code&gt; – Transform Data&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;When telling stories, it’s hard to resist embellishing them a little! And that’s where &lt;code&gt;map&lt;/code&gt; comes to the rescue, capable of transforming the data stream on the fly.&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="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;map&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;rxjs&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;obs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;n&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="nx"&gt;obs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&amp;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="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="c1"&gt;// Console output:&lt;/span&gt;
&lt;span class="c1"&gt;// 2&lt;/span&gt;
&lt;span class="c1"&gt;// 4&lt;/span&gt;
&lt;span class="c1"&gt;// 6&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;map&lt;/code&gt; takes &lt;em&gt;each value&lt;/em&gt; (e.g., a number, text, or object) from the stream.&lt;/li&gt;
&lt;li&gt;Transforms it as instructed by you.&lt;/li&gt;
&lt;li&gt;Passes the modified version of the data further.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Using &lt;code&gt;interval&lt;/code&gt; for Continuous Data&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The previous steps help us get familiar with the mechanisms of working with RxJS, but they don't really resemble anything asynchronous— the code executes instantly, with no waiting or delays. That's why we should include one more function in our starter set: &lt;code&gt;interval&lt;/code&gt;. It creates an infinite stream of numbers starting from 0, emitting them at a given time interval in milliseconds.&lt;/p&gt;

&lt;p&gt;Let's create an Observable that emits a new value every second:&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;interval&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;rxjs&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;timerObservable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Emit values every second.&lt;/span&gt;

&lt;span class="nx"&gt;timerObservable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&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;`One second passed: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;value&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="p"&gt;});&lt;/span&gt;
&lt;span class="c1"&gt;// Console output:&lt;/span&gt;
&lt;span class="c1"&gt;// One second passed: 0&lt;/span&gt;
&lt;span class="c1"&gt;// One second passed: 1&lt;/span&gt;
&lt;span class="c1"&gt;// One second passed: 2&lt;/span&gt;
&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This generator will help you slightly expand the base for experiments alongside the functions mentioned above.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Conclusion&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The main thing to remember is that mastering powerful tools like RxJS takes time. And that's completely normal. Honestly, no one becomes an expert in a single day.&lt;/p&gt;

&lt;p&gt;Don't try to understand everything at once or apply dozens of operators immediately. It’s easy to get lost when attempting to "embrace the immense." Start with the simplest concepts, with topics you already grasp to some extent: experiment with &lt;code&gt;from()&lt;/code&gt;, &lt;code&gt;interval()&lt;/code&gt;, &lt;code&gt;filter&lt;/code&gt;, and &lt;code&gt;map&lt;/code&gt; until you feel comfortable writing code with these topics without effort or confusion. Once you’ve achieved that ease, the next steps will be considerably simpler.&lt;/p&gt;

&lt;p&gt;Remember that every complex topic can be broken down into simpler parts. A deliberate, gradual approach is the key to making RxJS less of a confusing magic trick and more of a convenient, powerful tool that you’ll genuinely enjoy using.&lt;/p&gt;

&lt;p&gt;Don’t be afraid to make mistakes, ask questions, or return to basic examples. Everyone progresses differently, but each of us started from the basics at some point.&lt;/p&gt;

&lt;p&gt;In upcoming articles, we’ll explore how to make Observables even more powerful with other operators like &lt;code&gt;switchMap&lt;/code&gt;, &lt;code&gt;mergeMap&lt;/code&gt;, and others while trying to understand how to approach mastering this extensive list of operators properly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Happy Coding!&lt;/strong&gt;&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
