<?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: Ivan Novikov</title>
    <description>The latest articles on DEV Community by Ivan Novikov (@ivan7237d).</description>
    <link>https://dev.to/ivan7237d</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%2F569973%2F9ddd008a-1f76-4779-8a20-10dec13c6bd6.jpg</url>
      <title>DEV Community: Ivan Novikov</title>
      <link>https://dev.to/ivan7237d</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ivan7237d"/>
    <language>en</language>
    <item>
      <title>Cancelable async tasks and typed server errors with SolidJS and LazyPromise</title>
      <dc:creator>Ivan Novikov</dc:creator>
      <pubDate>Thu, 04 Dec 2025 02:20:45 +0000</pubDate>
      <link>https://dev.to/ivan7237d/cancelable-async-tasks-and-typed-server-errors-with-solidjs-and-lazypromise-1la</link>
      <guid>https://dev.to/ivan7237d/cancelable-async-tasks-and-typed-server-errors-with-solidjs-and-lazypromise-1la</guid>
      <description>&lt;h2&gt;
  
  
  Cancelable async tasks
&lt;/h2&gt;

&lt;p&gt;Let's begin with the question of why do we at all need to cancel async tasks. One argument is that if you've made a server request, it's already out there, and there isn't much point in aborting it. Let's take a look at a real-life example.&lt;/p&gt;

&lt;p&gt;Suppose you have a regular OTP code authentication flow. The user starts on a page like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbs2081x6g1kolbp2sesg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbs2081x6g1kolbp2sesg.png" alt="Email input screen for magic-link/OTP login" width="800" height="241"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then they enter an email, hit "Email Sign In Code", and end up on this page:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fedni8vwlm4tykr3b9znj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fedni8vwlm4tykr3b9znj.png" alt="OTP verification code entry screen" width="800" height="238"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The normal flow then is the user enters the code, we send a request with that code to the server, the server responds with a &lt;code&gt;Set-Cookie&lt;/code&gt; header, the user is now authenticated and we redirect them client-side to the app's dashboard. But what happens if while the request with the code is still in flight, the user realizes they actually want to sign in under a different email, and hit the "Go Back" button?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq0o0t4dhyzp62ssepxzq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq0o0t4dhyzp62ssepxzq.png" alt="OTP verification code entry screen with arrow pointing at Go Back button" width="800" height="238"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Well, we have here an example of when we definitely should actually abort the request at the browser level, else the user will receive the wrong cookie.&lt;/p&gt;

&lt;p&gt;A little while ago I wrote a primitive called LazyPromise which has an api that's only superficially different from that of a native Promise, but which is cancelable. A LazyPromise has a method &lt;code&gt;.subscribe(handleValue, handleError)&lt;/code&gt; that returns a disposal handle. Since I've recently had to port an app from React to Solid, I wrote the glue between LazyPromise and Solid, in particular a function &lt;code&gt;useLazyPromise&lt;/code&gt; that passes the disposal handle to Solid's &lt;code&gt;onCleanup&lt;/code&gt;, so you can write&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;useLazyPromise(myLazyPromise);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and be guaranteed that the async task will be canceled as soon as the Solid scope is disposed.&lt;/p&gt;

&lt;p&gt;A good question to ask at this point is why would you do something as adventurous as a DIY promise, when you could just write a Solid-specific wrapper around the native AbortSignal that you would use like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;useAbortablePromise(async (abortSignal) =&amp;gt; {
  // fetch things
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Well, the thing is that LazyPromise can be seen as simply such wrapper. There is a utility &lt;code&gt;lazy&lt;/code&gt; that turns an async function into a LazyPromise, and you can write&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;useLazyPromise(lazy(async (abortSignal) =&amp;gt; {
  // fetch things
}));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you are using functions like &lt;code&gt;async (abortSignal) =&amp;gt; ...&lt;/code&gt;, you are already essentially dealing in lazy promises, and if you use actual LazyPromise objects, you get &lt;a href="https://github.com/lazy-promise/lazy-promise/tree/main/packages/solid-js#createtrackprocessing" rel="noopener noreferrer"&gt;composability&lt;/a&gt; and a couple of benefits that I'll cover in the rest of this article.&lt;/p&gt;

&lt;h2&gt;
  
  
  Typed errors
&lt;/h2&gt;

&lt;p&gt;In my experience, it's been extremely useful to have the type system reflect errors that a server endpoint throws, because they all throw slightly different sets of errors and it's necessary to make sure that the right errors are handled on the client side. On the server I use the regular async-await, but if there is an error (user not authenticated, not authorized, 404 etc.), I return an object &lt;code&gt;{__error: ...}&lt;/code&gt; so the result type is &lt;code&gt;Data | {__error: Error}&lt;/code&gt; (if you prefer you could instead return &lt;code&gt;{data: Data} | {error: Error}&lt;/code&gt;). The client talks to the server via TRPC, and there is a wrapper that turns a TRPC response into a &lt;code&gt;LazyPromise&amp;lt;Data, Error&amp;gt;&lt;/code&gt; (&lt;a href="https://gist.github.com/ivan7237d/55c3e4d259fc7c6565ac68d80205552f" rel="noopener noreferrer"&gt;gist&lt;/a&gt;), so you could write something like&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;useLazyPromise(
  pipe(
    trpcLazyPromise(api.authn.checkOtpCode.mutate)(&amp;lt;params&amp;gt;),
    catchRejection((error) =&amp;gt; {
      // `error` is typed.
    }),
  ),
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You could in theory keep the return type of the server endpoint as &lt;code&gt;Data | {__error: Error}&lt;/code&gt; and this way capture the error type without resorting to a non-native promise, but it would break things like &lt;code&gt;Promise.all&lt;/code&gt;, make the code harder to read, and in the case when you're not doing anything with the return value (like the authentication example), TypeScript isn't going to notice if you forget to handle the errors.&lt;/p&gt;

&lt;p&gt;There's a popular library called Effect which I haven't used, but I think typed errors is its major selling point. Here you get typed errors, but with a primitive-based approach where instead of having a whole new API to learn, you get LazyPromise API which in spirit maps one-to-one to the native Promise.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus: no microtaks
&lt;/h2&gt;

&lt;p&gt;We've covered above two ways a LazyPromise differs from a native Promise (laziness/cancelability and typed errors), but there is a third and final one: LazyPromise fires synchronously instead of in a microtask. That works really well with SolidJS. We've looked above at the utility &lt;code&gt;useLazyPromise&lt;/code&gt; that just subscribes to a LazyPromise and which you'd typically use with mutations, but there's also one called &lt;code&gt;createFetcher&lt;/code&gt; which lets you use LazyPromise with &lt;code&gt;createResource&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const [accessor] = createResource(
  createFetcher(() =&amp;gt; yourLazyPromise)
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The fun thing is what happens when the lazy promise resolves synchronously. This:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const [accessor] = createResource(
  count,
  // `resolved` is LazyPromise equivalent of Promise.resolve.
  createFetcher((count: number) =&amp;gt; resolved(count)),
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;behaves in the same way diamond-problem-wise as this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const [accessor] = createResource(
  count,
  (count: number) =&amp;gt; count,
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;as opposed to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const [accessor] = createResource(
  count,
  (count: number) =&amp;gt; Promise.resolve(count),
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;LazyPromise is a very well unit-tested (including for memory leaks) and stable enough library available &lt;a href="https://github.com/lazy-promise/lazy-promise" rel="noopener noreferrer"&gt;here&lt;/a&gt;. The SolidJS bindings are still experimental as of this writing and available &lt;a href="https://github.com/lazy-promise/lazy-promise/tree/main/packages/solid-js" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>solidjs</category>
      <category>typescript</category>
      <category>async</category>
      <category>javascript</category>
    </item>
    <item>
      <title>I've used the pipe() function 2,560 times and I can tell you it's good!</title>
      <dc:creator>Ivan Novikov</dc:creator>
      <pubDate>Wed, 03 Mar 2021 20:11:42 +0000</pubDate>
      <link>https://dev.to/ivan7237d/i-ve-used-the-pipe-function-2-560-times-and-i-can-tell-you-it-s-good-4aal</link>
      <guid>https://dev.to/ivan7237d/i-ve-used-the-pipe-function-2-560-times-and-i-can-tell-you-it-s-good-4aal</guid>
      <description>&lt;p&gt;The &lt;code&gt;pipe()&lt;/code&gt; function that I'm talking about is the one that lets you replace &lt;code&gt;b(a(x))&lt;/code&gt; with &lt;code&gt;pipe(x, a, b)&lt;/code&gt;. Yes, that's how many times I've used it over the last few years, and looking back at those usages, I'd like to tell you the reasons you might find it useful too, even when you work with a codebase that doesn't stray from mainstream patterns into functional programming.&lt;/p&gt;

&lt;h1&gt;
  
  
  Where it's coming from
&lt;/h1&gt;

&lt;p&gt;&lt;code&gt;pipe&lt;/code&gt; takes the first argument and pipes it though each of the functions that you provide as the remaining arguments, and can be implemented as follows:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pipe&lt;/span&gt; &lt;span class="o"&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="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;fns&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;fns&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;el&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;el&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;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;You can &lt;a href="https://github.com/ivan7237d/antiutils/blob/master/src/internal/pipe.ts" rel="noopener noreferrer"&gt;type it in TypeScript&lt;/a&gt; using overloads, and since as far back as TypeScript 3.4, type inference works perfectly:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft2g0loj6eil9bbue9taz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft2g0loj6eil9bbue9taz.png" alt="Screenshot showing an IntelliSense tooltip" width="800" height="112"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One way to look at this function is to see it as a fill-in for the proposed pipeline operator (&lt;code&gt;x |&amp;gt; a |&amp;gt; b&lt;/code&gt;). That proposal has been at stage 1 for years, but the good news is that &lt;code&gt;pipe&lt;/code&gt; is not far worse — curiously, it's even better than some of the discussed flavors of the operator in one sense, namely that you don't have to enclose arrow functions in parens. If one of the flavors of the pipeline operator does reach stage 3, you won't be left out in the cold: with AST tools and Prettier, it would be easy to build a codemod that replaces &lt;code&gt;pipe&lt;/code&gt; with the operator.&lt;/p&gt;

&lt;p&gt;Putting aside the pipeline operator, &lt;code&gt;pipe&lt;/code&gt; can be just seen as the first choice among different ways to do function composition. Another notable contender is a function that composes functions without applying them,&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ltrCompose&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;fns&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;x&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;fns&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;el&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;fn&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;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;so &lt;code&gt;b(a(x))&lt;/code&gt; is equivalent to &lt;code&gt;ltrCompose(a, b)(x)&lt;/code&gt;. It's a higher-order function though, and that's where &lt;code&gt;pipe&lt;/code&gt; beats it: &lt;code&gt;pipe&lt;/code&gt; is easier to read because it lets you achieve the same ends without thinking in terms of transforming functions to other functions. At first I tried using both utilities depending on the context, but I found this to be a bad violation of "only one way to do it".&lt;/p&gt;
&lt;h1&gt;
  
  
  It's like dot-chaining
&lt;/h1&gt;

&lt;p&gt;Now to reasons for using &lt;code&gt;pipe&lt;/code&gt;. The first thing to notice is that rather than introducing a new pattern, &lt;code&gt;pipe&lt;/code&gt; lets you use essentially the same pattern as dot-chaining,&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="nx"&gt;yourArray&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;predicate&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;project&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;yourString&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;only without being constrained to the collection of methods defined for native objects.&lt;/p&gt;

&lt;p&gt;One group of use-cases center around the fact that native JavaScript APIs were not designed with an eye to immutable updates that we often use today. &lt;code&gt;sort&lt;/code&gt; method of &lt;code&gt;Array&lt;/code&gt; and &lt;code&gt;add&lt;/code&gt; method of &lt;code&gt;Set&lt;/code&gt; are mutating, but with &lt;code&gt;pipe&lt;/code&gt;, we can define their non-mutating counterparts&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sort&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;compare&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;array&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;array&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;compare&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;add&lt;/span&gt; &lt;span class="o"&gt;=&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="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;set&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;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;set&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="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;and use them like we use dot-chained methods:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newArray&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;compare&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;newSet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;set&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="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Another common use-case is iterables. To take one example, if you need to filter values of a &lt;code&gt;Map&lt;/code&gt;, you would have to write &lt;code&gt;[...yourMap.values()].filter(predicate)&lt;/code&gt;, in other words, you have to convert the iterable returned by &lt;code&gt;yourMap.values&lt;/code&gt; to an array just to get at the &lt;code&gt;filter&lt;/code&gt; method. It wouldn't matter that much if it was just a question of performance, but it's both inefficient &lt;em&gt;and&lt;/em&gt; clutters up the code. &lt;code&gt;pipe&lt;/code&gt; gives you an alternative of working with iterables in the same way that you work with arrays:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;filter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;predicate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;iterable&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;el&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;iterable&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="nf"&gt;predicate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="nx"&gt;el&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;filteredValuesIterable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;yourMap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;values&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;predicate&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;h1&gt;
  
  
  It lets you create locals with expressions
&lt;/h1&gt;

&lt;p&gt;Here's another reason for using &lt;code&gt;pipe&lt;/code&gt; — and this time we're not even going to need any utility functions other than &lt;code&gt;pipe&lt;/code&gt; itself.&lt;/p&gt;

&lt;p&gt;Imagine that in an &lt;code&gt;if&lt;/code&gt; clause, you need to convert a string to a number and check if that number is greater than 0.&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;parseFloat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;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="c1"&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 suppose that we also need to check that the number is less than 1. Unless we want to duplicate &lt;code&gt;parseFloat&lt;/code&gt; calls, we have to define a new constant in the outer scope:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parseFloat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;str&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;num&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&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="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Wouldn't it be better if &lt;code&gt;num&lt;/code&gt; was scoped to the expression in the &lt;code&gt;if&lt;/code&gt; clause, which is the only place where we need it? This can be accomplished with an IIFE, but it's not pretty:&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;((()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parseFloat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;str&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;num&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&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="p"&gt;{&lt;/span&gt; 
  &lt;span class="c1"&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;code&gt;pipe&lt;/code&gt; solves the problem:&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="k"&gt;if &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="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;parseFloat&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&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;num&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&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="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Generally speaking, in any context where an expression is expected, whether it's a function argument, an element in an array/object literal, or an operand of a ternary operator, &lt;code&gt;pipe&lt;/code&gt; lets you create a local without resorting to IIFE. This tends to make you rely more on expressions,&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;reducer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;action&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;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="s2"&gt;`incrementA`&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="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&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="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;rest&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="nx"&gt;rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;a&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="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="s2"&gt;`incrementB`&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="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&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="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;rest&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="nx"&gt;rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;b&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="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;but you don't have to use expressions all the time — &lt;code&gt;pipe&lt;/code&gt; just lets you make the choice between expressions and statements not based on syntax limitations, but based on what's more readable in a specific situation.&lt;/p&gt;



&lt;p&gt;The &lt;code&gt;pipe&lt;/code&gt; function as defined here is available in &lt;a href="https://gcanti.github.io/fp-ts/modules/function.ts.html#pipe" rel="noopener noreferrer"&gt;fp-ts&lt;/a&gt;. If like me you don't need a full-blown functional programming library, you can get &lt;code&gt;pipe&lt;/code&gt; in my own library Antiutils: &lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/ivan7237d" rel="noopener noreferrer"&gt;
        ivan7237d
      &lt;/a&gt; / &lt;a href="https://github.com/ivan7237d/pipe-function" rel="noopener noreferrer"&gt;
        pipe-function
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A function to pipe a value through a number of transforms
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;
&lt;code&gt;pipe&lt;/code&gt; function&lt;/h1&gt;

&lt;/div&gt;

&lt;p&gt;A function to pipe a value through a number of transforms.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Installation&lt;/h2&gt;

&lt;/div&gt;

&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;npm install pipe-function&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;or&lt;/p&gt;

&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;yarn add pipe-function&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;or&lt;/p&gt;

&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;pnpm add pipe-function&lt;/pre&gt;

&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Usage&lt;/h2&gt;

&lt;/div&gt;

&lt;div class="highlight highlight-source-ts notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;import&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt; &lt;span class="pl-s1"&gt;pipe&lt;/span&gt; &lt;span class="pl-kos"&gt;}&lt;/span&gt; &lt;span class="pl-k"&gt;from&lt;/span&gt; &lt;span class="pl-s"&gt;"pipe-function"&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Takes between 1 and 20 arguments. &lt;code&gt;pipe(x, a, b)&lt;/code&gt; is equivalent to &lt;code&gt;b(a(x))&lt;/code&gt;, in other words, this function pipes a value through a number of functions in the order that they appear. &lt;a href="https://dev.to/ivan7237d/i-ve-used-the-pipe-function-2-560-times-and-i-can-tell-you-it-s-good-4aal" rel="nofollow"&gt;This article&lt;/a&gt; talks about why this function is useful.&lt;/p&gt;

&lt;/div&gt;
&lt;br&gt;
&lt;br&gt;
  &lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/ivan7237d/pipe-function" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


</description>
      <category>javascript</category>
      <category>typescript</category>
      <category>functional</category>
    </item>
    <item>
      <title>Log and test RxJS observables with 1log</title>
      <dc:creator>Ivan Novikov</dc:creator>
      <pubDate>Mon, 01 Feb 2021 15:49:27 +0000</pubDate>
      <link>https://dev.to/ivan7237d/log-and-test-rxjs-observables-with-1log-5cbm</link>
      <guid>https://dev.to/ivan7237d/log-and-test-rxjs-observables-with-1log-5cbm</guid>
      <description>&lt;p&gt;&lt;strong&gt;ATTENTION: this article is now outdated, please see &lt;a href="https://github.com/ivan7237d/1log/tree/master/packages/rxjs" rel="noopener noreferrer"&gt;GitHub readme&lt;/a&gt; for the current version of the API.&lt;/strong&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Logging
&lt;/h1&gt;

&lt;p&gt;As soon as I started building an app that uses RxJS, I realized that I needed a logging utility. First I went with a common approach of creating a custom operator 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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;log&lt;/span&gt; &lt;span class="o"&gt;=&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="nx"&gt;label&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;MonoTypeOperatorFunction&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;=&amp;gt;&lt;/span&gt;
  &lt;span class="nf"&gt;tap&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="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="nx"&gt;label&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="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="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;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;label&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="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;label&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;complete&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;At some point though, I ran into debugging scenarios where I needed more information than nexts, errors, and completions — at a minimum,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A way to tell when an observable is created, subscribed and unsubbed.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When some observable is subscribed multiple times, a way to tell which subscription a next/error/complete/unsub originates from.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So I came up with &lt;a href="https://github.com/ivan7237d/1log-rxjs" rel="noopener noreferrer"&gt;1log&lt;/a&gt;. Let's jump straight to a basic code snippet and take a look at the log messages that it produces:&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;log&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;1log&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;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="nf"&gt;timer&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;pipe&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="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;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fqpqj0nd00cwltxmwfo2l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fqpqj0nd00cwltxmwfo2l.png" alt="Screenshot" width="800" height="191"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For the most part, the messages are self-explanatory, but there are a few things to note while we're at it.&lt;/p&gt;

&lt;p&gt;Time deltas are muted if they are less than 10ms and bold if they are 1s or more. They are computed using &lt;code&gt;performance.now&lt;/code&gt; (so the first delta is counted from the time the user &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/DOMHighResTimeStamp#The_time_origin" rel="noopener noreferrer"&gt;started navigation&lt;/a&gt; that opened the page) and exclude the time spent on logging itself.&lt;/p&gt;

&lt;p&gt;The indentation (as in the last line in the above screenshot) indicates synchronous stack level. One situation where this is handy is &lt;a href="https://stackoverflow.com/questions/48233498/why-do-my-rxjs-state-changes-show-up-out-of-order" rel="noopener noreferrer"&gt;reentrancy-related bugs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Colors and other styling is supported in all recent desktop browsers (where it's implemented using &lt;code&gt;%c&lt;/code&gt; directive) and in Node/terminal (where it's implemented using ANSI escape codes).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Tip:&lt;/em&gt; In Chrome, you can right-click an observable or a subscriber from a "create" or "subscribe" log message and say "Store as global variable". The object will be stored with a name like &lt;code&gt;temp1&lt;/code&gt;. It's sometimes useful to have access to this object in the console, for example to call next on a subscriber.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Library core
&lt;/h1&gt;

&lt;p&gt;Now let's take a closer look at the library's API.&lt;/p&gt;

&lt;p&gt;The logic specific to RxJS observables is in package &lt;a href="https://github.com/ivan7237d/1log-rxjs" rel="noopener noreferrer"&gt;&lt;code&gt;1log-rxjs&lt;/code&gt;&lt;/a&gt;, while the library core is in package  &lt;a href="https://github.com/ivan7237d/1log" rel="noopener noreferrer"&gt;&lt;code&gt;1log&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The core exports a function &lt;code&gt;log&lt;/code&gt; which can be used like just like the regular &lt;code&gt;console.log&lt;/code&gt;, but has two superpowers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;When passed a single argument, it returns that argument or a proxy that mimics it. This means that &lt;code&gt;log&lt;/code&gt; can be inserted into any expression without changing the behavior of your program, e.g. &lt;code&gt;f(log(x))&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It supports plugins. There are two ways to install a plugin: you can install a plugin locally by passing it as an argument to &lt;code&gt;log&lt;/code&gt;, in which case &lt;code&gt;log&lt;/code&gt; will return a function just like itself, but with the plugin installed — or you can install a plugin globally by calling &lt;code&gt;installPlugin(yourPlugin)&lt;/code&gt; before any &lt;code&gt;log&lt;/code&gt; calls.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The package &lt;code&gt;1log-rxjs&lt;/code&gt; exports a plugin called &lt;code&gt;observablePlugin&lt;/code&gt;. It's installed globally with the default config, and affects how the &lt;code&gt;log&lt;/code&gt; function behaves when you give it an RxJS observable, as in &lt;code&gt;log(yourObservable)&lt;/code&gt; or equivalently &lt;code&gt;yourObservable.pipe(log)&lt;/code&gt;. Instead of passing &lt;code&gt;yourObsevable&lt;/code&gt; through as is, &lt;code&gt;log&lt;/code&gt; will return a proxy that's like the original, but logs everything that's happening to it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Tip:&lt;/em&gt; Instances of classes like &lt;code&gt;Subject&lt;/code&gt; that inherit from &lt;code&gt;Observable&lt;/code&gt; will not be proxied — to log a subject, first convert it to an observable using method &lt;code&gt;asObservable&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The core library has a bunch of features that you can read about in its &lt;a href="https://github.com/ivan7237d/1log" rel="noopener noreferrer"&gt;GitHub readme&lt;/a&gt;: it provides plugins similar to &lt;code&gt;observablePlugin&lt;/code&gt;, but for functions, promises and iterables; it also supports severity levels, optimized production builds and usage in libraries. What I'd like to do here though is talk about a plugin included in the core called &lt;code&gt;badgePlugin&lt;/code&gt;, and at the same time give you another, slightly more complex example of using 1log.&lt;/p&gt;

&lt;p&gt;As I mentioned, you can install a plugin locally by passing it to the &lt;code&gt;log&lt;/code&gt; function. In particular, &lt;code&gt;log(badgePlugin('your caption'))&lt;/code&gt; will return a function just like &lt;code&gt;log&lt;/code&gt;, but which prefixes log messages with a badge. Let's see what messages are logged by the following 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;badgePlugin&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="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1log&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;fromEvent&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;switchMap&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;click&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="nf"&gt;pipe&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="nf"&gt;badgePlugin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;outer&lt;/span&gt;&lt;span class="dl"&gt;'&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="nf"&gt;timer&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;pipe&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="nf"&gt;badgePlugin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;inner&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;p&gt;Two messages appear as soon as the page loads:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F5y2diik6noc483k75ch6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F5y2diik6noc483k75ch6.png" alt="Screenshot" width="800" height="116"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this example, 2.35 seconds later I click somewhere in the page, and this immediately produces three more messages:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F7bfo9g3zq19m6nxdasfv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F7bfo9g3zq19m6nxdasfv.png" alt="Screenshot" width="800" height="163"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Notice that for the inner observable the badge says "create 1", not "create 2": that's because there are separate counters for inner and outer observables, or generally speaking, for each combination of preceding badges.&lt;/p&gt;

&lt;p&gt;What happened so far is that my click started the 500ms timer inside &lt;code&gt;switchMap&lt;/code&gt; — but in 157ms, before the timer has had the chance to fire, I click again, and &lt;code&gt;switchMap&lt;/code&gt; switches to a new timer, which eventually fires:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fgvj81o2voahg4ff293nm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fgvj81o2voahg4ff293nm.png" alt="Screenshot" width="800" height="262"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Testing
&lt;/h1&gt;

&lt;p&gt;In combination with Jest's snapshots feature, inspecting log messages is a great way to test observables.&lt;/p&gt;

&lt;p&gt;You can configure the library in such a way that when running tests, log messages are placed in a buffer instead of writing them to the console. You can retrieve them from that buffer and clear it by calling &lt;code&gt;getMessages()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let's take a look at an example. I launch Jest in watch mode and create the following &lt;code&gt;.test.ts&lt;/code&gt; / &lt;code&gt;.test.js&lt;/code&gt; file:&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;getMessages&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="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1log&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;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="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;timer&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&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;500&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="nx"&gt;log&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;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;runAllTimers&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;getMessages&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;toMatchInlineSnapshot&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;Once I save this file, Jest fills in the snapshot and there you go, I have a comprehensive and easy-to-read test:&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;getMessages&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="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1log&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;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="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;timer&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&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;500&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="nx"&gt;log&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;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;runAllTimers&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;getMessages&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;toMatchInlineSnapshot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`
    [create 1] +0ms [Observable]
    [create 1] [subscribe 1] +0ms [Subscriber]
    [create 1] [subscribe 1] [next] +500ms 0
    [create 1] [subscribe 1] [complete] +0ms
    · [create 1] [subscribe 1] [unsubscribe] +0ms
  `&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;Since colors are not available in tests, badges like &lt;code&gt;[create 1]&lt;/code&gt; are not shortened to &lt;code&gt;[1]&lt;/code&gt; the way they are in the console.&lt;/p&gt;




&lt;p&gt;P.S. Together with 1log I published a utilities library which I called &lt;a href="https://github.com/ivan7237d/antiutils" rel="noopener noreferrer"&gt;Antiutils&lt;/a&gt;, and which is 1log's only dependency. Check it out if you're curious.&lt;/p&gt;

</description>
      <category>rxjs</category>
      <category>logging</category>
      <category>testing</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
