<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>phryneas.de</title>
    <description></description>
    <link>https://www.phryneas.de/</link>
    <atom:link href="https://www.phryneas.de/feed.xml" rel="self" type="application/rss+xml" />
    <pubDate>Sat, 11 Apr 2026 09:46:48 +0000</pubDate>
    <lastBuildDate>Sat, 11 Apr 2026 09:46:48 +0000</lastBuildDate>
    <generator>Jekyll v3.8.6</generator>
    
      <item>
        <title>Talks &amp; Slides for React Advanced 2024 - Beyond React Testing Library: Testing React Libraries (and library-like code)</title>
        <description>&lt;p&gt;And another visit to London and the amazing React Advanced conference, where I announced &lt;a href=&quot;https://github.com/testing-library/react-render-stream-testing-library&quot;&gt;@testing-library/react-render-stream&lt;/a&gt; to the world.&lt;/p&gt;

&lt;h2 id=&quot;beyond-react-testing-library-testing-react-libraries-and-library-like-code&quot;&gt;Beyond React Testing Library: Testing React Libraries (and library-like code)&lt;/h2&gt;
&lt;details class=&quot;abstract&quot;&gt;
&lt;summary&gt;
Abstract (click to expand)
&lt;/summary&gt;
&lt;cite&gt;&lt;div&gt;
      &lt;p&gt;When it comes to testing library code, the (usually amazing!) “Testing Library” approach quickly hits its limitations: We often need to test hot code paths to ensure additional guarantees, such as a specific order of DOM changes or a particular number of renders.&lt;/p&gt;

      &lt;p&gt;As soon as we start adding Suspense to the picture, it even gets almost philosophical:&lt;/p&gt;

      &lt;ul&gt;
        &lt;li&gt;
          &lt;p&gt;How do we count a render that immediately suspended, and how do we distinguish it from a “committed” render?&lt;/p&gt;
        &lt;/li&gt;
        &lt;li&gt;
          &lt;p&gt;How do we know which parts of the Component tree rerendered?&lt;/p&gt;
        &lt;/li&gt;
      &lt;/ul&gt;

      &lt;p&gt;In the Apollo Client code base, we’re using the React Profiler to create a stream of render events, enabling us to switch to a new stream-based testing method.&lt;/p&gt;

      &lt;p&gt;After testing this approach internally for a year, we have released it in a library that we want to present to the world.&lt;/p&gt;
    &lt;/div&gt;&lt;/cite&gt;
&lt;/details&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://gitnation.com/contents/beyond-react-testing-library-testing-react-libraries-and-library-like-code&quot;&gt;Video&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Fri, 25 Oct 2024 00:00:00 +0000</pubDate>
        <link>https://www.phryneas.de/react_advanced-london-2024-talk</link>
        <guid isPermaLink="true">https://www.phryneas.de/react_advanced-london-2024-talk</guid>
        
        
      </item>
    
      <item>
        <title>Talks &amp; Slides for enterJS React 19 day - Was passiert eigentlich in einer App mit RSC so unter der Haube?</title>
        <description>&lt;p&gt;A very fun remote deep dive I did in German at enterJS React 19 day. 
Unfortunately I don’t think it has been recorded, but the slides should tell a story on their own.&lt;/p&gt;

&lt;h2 lang=&quot;de&quot;&gt;Was passiert eigentlich in einer App mit RSC so unter der Haube?&lt;/h2&gt;
&lt;details class=&quot;abstract&quot;&gt;
&lt;summary&gt;
Abstract (click to expand)
&lt;/summary&gt;
&lt;cite&gt;&lt;div lang=&quot;de&quot;&gt;
      &lt;p&gt;Nehmen wir an, wir haben eine App mit ein paar Serverkomponenten und ein paar Clientkomponenten. Was passiert da eigentlich auf dem Weg vom Server zum Server (ja, richtig!) zum Browser?&lt;/p&gt;

      &lt;p&gt;Ein paar kleine Spoiler: Es gibt mindestens einen Stream im Stream. Manchmal transportiert der Stream im Stream sogar noch weitere Streams. Darüber hinaus spielen noch eine Handvoll neuer Pakete (manchmal auch dasselbe Paket in unterschiedlichen Ausführungen) und Bundler-Plug-ins eine Rolle.&lt;/p&gt;

      &lt;p&gt;Wir schauen uns das an, und wenn die Zeit reicht werfen wir sogar einen Blick in den React SourceCode.&lt;/p&gt;
    &lt;/div&gt;&lt;/cite&gt;
&lt;/details&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://drive.google.com/file/d/1lYpu_oSS9FyObsTtQu_PRIDA8dyOjMGk/view?usp=sharing&quot;&gt;Slides&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Thu, 17 Oct 2024 00:00:00 +0000</pubDate>
        <link>https://www.phryneas.de/enterjs-react-19-day-2024-talk</link>
        <guid isPermaLink="true">https://www.phryneas.de/enterjs-react-19-day-2024-talk</guid>
        
        
      </item>
    
      <item>
        <title>Talks &amp; Slides for React Advanced London 2023 - The Rocky Journey of Data Fetching Libraries in React’s New Streaming SSR</title>
        <description>&lt;p&gt;I was at React Advanced to talk about all the stuff data fetching library authors have to do to support streaming SSR.&lt;/p&gt;

&lt;h2 id=&quot;the-rocky-journey-of-data-fetching-libraries-in-reacts-new-streaming-ssr&quot;&gt;The Rocky Journey of Data Fetching Libraries in React’s New Streaming SSR&lt;/h2&gt;
&lt;details class=&quot;abstract&quot;&gt;
&lt;summary&gt;
Abstract (click to expand)
&lt;/summary&gt;
&lt;cite&gt;&lt;div&gt;
      &lt;p&gt;If you use the Next.js app directory, you might not even have noticed it, but you are not only using React Server Components, but you are also using the new streaming SSR feature of React.&lt;/p&gt;

      &lt;p&gt;That means that on first page load, your Client Components will now be server-side rendered, suspense boundary by suspense boundary, and constantly streamed to the client, where they are rehydrated piece-by-piece.&lt;/p&gt;

      &lt;p&gt;If you combine that with suspense for data fetching in your client components, you will suddenly be facing hydration mismatches - as your client components will start fetching data on the server, but the data will not be transported to the client.&lt;/p&gt;

      &lt;p&gt;In this talk, I will go over the rocky journey that we had to go through to support suspense for data fetching in Streaming SSR with Apollo Client, looking at all the curious timing problems that come up with these technologies, and how we try to solve them as best as we can - always with the best possible user and developer experience in mind.&lt;/p&gt;
    &lt;/div&gt;&lt;/cite&gt;
&lt;/details&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/phryneas/react-advanced-talk-suspense-streaming-ssr&quot;&gt;Slides (yes, the slides are an app)&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://gitnation.com/contents/the-rocky-journey-of-data-fetching-libraries-in-reacts-new-streaming-ssr&quot;&gt;Video&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Mon, 23 Oct 2023 00:00:00 +0000</pubDate>
        <link>https://www.phryneas.de/react_advanced-london-2023-talk</link>
        <guid isPermaLink="true">https://www.phryneas.de/react_advanced-london-2023-talk</guid>
        
        
      </item>
    
      <item>
        <title>My take on the current React &amp; Server Components controversy</title>
        <description>&lt;p&gt;There has been a lot of frustration in tech Twitter over the last few weeks.&lt;br /&gt;
Some people are frustrated with React Server Components, and some are frustrated with the way the React team communicates.&lt;br /&gt;
The React team is frustrated with that “pile-on” they are facing.&lt;br /&gt;
And everyone is right on their own terms, but we all communicate it in the most unproductive ways.&lt;/p&gt;

&lt;p&gt;Twitter is notorious for this kind of discussion because nuance is lost due to its 280-character limit. But I still would like to explain my take on all of this.&lt;br /&gt;
So I’ll try to write a blog post instead.&lt;/p&gt;

&lt;!--snip--&gt;

&lt;p&gt;Disclaimer: I’m explaining how things feel or felt to me. A lot of this is highly subjective. Other people might feel differently about the same things. I might just not have noticed things happening, which could have saved me a ton of frustration. This is my personal story, how I experienced it.&lt;/p&gt;

&lt;h2 id=&quot;i-love-react-server-components&quot;&gt;I love React Server Components&lt;/h2&gt;

&lt;p&gt;I love React Server Components. They are a super cool feature. It’s an amazing step forward.&lt;br /&gt;
But I am also super frustrated by the place I find myself in right now, wanting to support them.&lt;/p&gt;

&lt;h2 id=&quot;i-want-you-to-understand-my-frustration&quot;&gt;I want you to understand my frustration&lt;/h2&gt;

&lt;p&gt;I’m a library maintainer. I am one of the maintainers of Apollo Client, Redux Toolkit and RTK Query. My job (in the case of Apollo) and hobby (in the case of the other two) is to make these libraries as easy &amp;amp; productive to use for their consumers as possible. I love to do that.&lt;/p&gt;

&lt;h3 id=&quot;helping-users-has-gotten-harder&quot;&gt;Helping users has gotten harder&lt;/h3&gt;

&lt;p&gt;But it has suddenly gotten a lot harder. People come to me with strange problems, and I can’t solve all of those for them.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;People on StackOverflow are facing error messages they don’t understand. Turns out they created a new React project with the first recommendation on the React homepage and then just applied default settings.&lt;br /&gt;
They don’t know what a Server Component is, but they are writing Server Components now.&lt;br /&gt;
None of the three libraries works in Server Components as it did before. Apollo needs an extra library; the Redux-based libraries don’t really have RSC support at this point in time. I’ll get to the “why” on that later.&lt;br /&gt;
I can’t give them a 3-hour lesson on StackOverflow, and honestly, I also don’t really know where to point them.&lt;br /&gt;
There is not a lot of documentation that really explains why what they are doing doesn’t work, or how to do it better.&lt;br /&gt;
So I just tell them, “please use &lt;code class=&quot;highlighter-rouge&quot;&gt;problematic-library&lt;/code&gt; only in Client Components”.&lt;br /&gt;
I don’t really feel like I’m helping people with that.&lt;/li&gt;
  &lt;li&gt;People come to us with bug reproductions that I don’t understand. Right now, I’m finding myself in the weird situation where I have to assume that this bug that people come to me with might not be in my library code, or in their code, but a React bug.&lt;br /&gt;
I recently spent two hours debugging an infinite loop. I was already at the point where I mocked out &lt;code class=&quot;highlighter-rouge&quot;&gt;useSyncExternalStore&lt;/code&gt; when I remembered that I had seen someone else mention the issue on Twitter.&lt;br /&gt;
Turns out their code had an &lt;code class=&quot;highlighter-rouge&quot;&gt;async&lt;/code&gt; component. Yes, their bug, but in the past, React would just have errored out with &lt;code class=&quot;highlighter-rouge&quot;&gt;&quot;Objects are not valid as a React child (found: [object Promise]).&quot;&lt;/code&gt; - but this is Next.js, shipping a canary version of React that allows Client Components to be &lt;code class=&quot;highlighter-rouge&quot;&gt;async&lt;/code&gt;.&lt;br /&gt;
And that actually worked in an older canary.&lt;br /&gt;
But not in the newest one. And since this feature is &lt;em&gt;there, but not documented as stable yet&lt;/em&gt;, the warning message has been removed and instead, we see this infinite loop.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;understanding-things-has-gotten-harder&quot;&gt;Understanding things has gotten harder&lt;/h3&gt;

&lt;p&gt;Apart from that, of course, I am working actively on making our libraries better for our users - in all three environments that currently seem relevant: in React Server Components, in Client Components rendering on the server and streaming to the browser, and in Client Components on the browser.&lt;br /&gt;
Honestly, when I started this, I’ve never felt as lost before.&lt;br /&gt;
There was no public guidance on anything beyond basic RSC usage, and the Next.js docs - while they were already very good - were definitely not aimed at someone who would be writing a library.&lt;br /&gt;
I had to gather most of my information from Twitter discussions. At one point, Dan Abramov sat down with me on a video call and did a lot of explaining - and then later, he spent hours going over my &lt;a href=&quot;https://github.com/apollographql/apollo-client-nextjs/pull/9&quot;&gt;RFC&lt;/a&gt; where I tried to write down what I had learned and corrected my misunderstandings and errors.&lt;br /&gt;
I am incredibly grateful for that, but at the same time, I look at all of the other React users out there, and I’m frustrated again.&lt;/p&gt;

&lt;p&gt;Not everyone out there has a Dan sitting down with them and guiding them through this.&lt;br /&gt;
How frustrating an experience must this be for everyone?&lt;/p&gt;

&lt;h3 id=&quot;writing-and-maintaining-a-widely-used-library-has-gotten-harder&quot;&gt;Writing and maintaining a widely used library has gotten harder&lt;/h3&gt;

&lt;p&gt;The bundler is frustrating me to no end. Files imported from React Server Components are statically analyzed. If they contain any reference to hooks like &lt;code class=&quot;highlighter-rouge&quot;&gt;useState&lt;/code&gt;, &lt;a href=&quot;https://github.com/apollographql/apollo-client/issues/10974&quot;&gt;the bundler errors out&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The solution is that libraries now should ship one more entry point, aimed at React Server Components, that doesn’t contain any APIs referencing those hooks. This is already a big moment of frustration. You don’t just “add a new entry point”. Changing anything about a library’s bundler setup is like open heart surgery. One wrong move, and one of your other artifacts changes and breaks in a bunch of bundlers that worked before. It’s nerve-wracking and, frankly, something I’d want to avoid whenever I can. But okay, let’s assume that the ecosystem needs to go through all of this churn. Let’s also assume that I’m willing to essentially duplicate my whole library with RSC-friendly alternatives to all the exports I had in place before.&lt;/p&gt;

&lt;p&gt;Now, this new entry point has to be added to the &lt;code class=&quot;highlighter-rouge&quot;&gt;exports&lt;/code&gt; field in your &lt;code class=&quot;highlighter-rouge&quot;&gt;package.json&lt;/code&gt;. If you already have an &lt;code class=&quot;highlighter-rouge&quot;&gt;exports&lt;/code&gt; field, that’s not a problem. If you don’t have it, you’re back at the “breaking bundlers” stage. You can effectively only do that in a major version. This is a big no-go for all libraries that weren’t already planning a new major. (The Redux ecosystem is already at the stage where we were planning for a major anyways, so I’d say here we are lucky.)&lt;br /&gt;
If you can’t add that &lt;code class=&quot;highlighter-rouge&quot;&gt;exports&lt;/code&gt; field, there is a workaround: If you don’t import the hooks from React as named imports, but as namespace imports - &lt;code class=&quot;highlighter-rouge&quot;&gt;import * as React from 'react'&lt;/code&gt;, current bundlers won’t pick up on that.&lt;/p&gt;

&lt;p&gt;Let’s just hope we’ll have that workaround going into the future. I really don’t want to release a new major of Apollo Client just to ship a new entrypoint for RSCs, even if our users don’t use any of the Client-Component specific features.&lt;br /&gt;
Every major version we release will leave users behind (people are still migrating from Apollo Client v2 to v3, and v3 released in 2019!), and releasing a new version of a multi-platform library just to cater to a change in React feels wrong in that regard.&lt;/p&gt;

&lt;p&gt;There’s also another pain point here that would be solved by shipping essentially a second RSC-friendly library as an alternative entrypoint, but that, in the meantime, has cost me enough frustration on it’s own, so I want to mention it: &lt;code class=&quot;highlighter-rouge&quot;&gt;createContext&lt;/code&gt; is not available in RSC. So the &lt;code class=&quot;highlighter-rouge&quot;&gt;ReactReduxContext&lt;/code&gt; that was a top-level export from &lt;code class=&quot;highlighter-rouge&quot;&gt;react-redux&lt;/code&gt; could not be created and importing &lt;code class=&quot;highlighter-rouge&quot;&gt;react-redux&lt;/code&gt; in a RSC environment was always a crash. &lt;a href=&quot;https://github.com/reduxjs/react-redux/pull/2025&quot;&gt;This workaround is horrifying.&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;it-feels-like-the-browser-is-being-ignored-and-there-is-no-feedback-loop&quot;&gt;It feels like the browser is being ignored, and there is no feedback loop&lt;/h3&gt;

&lt;p&gt;When React 18 released, it shipped with Concurrent Mode, and Suspense was declared “stable” - with one little exception: Suspense for data fetching in the browser was not. So we were good ecosystem citizens and waited, and from time to time, someone dropped into our issues and asked why the library still had no support, and we pointed them to the React 18 release notes and shrugged.&lt;br /&gt;
At some point, the &lt;a href=&quot;https://github.com/reactjs/rfcs/pull/229&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;use&lt;/code&gt; RFC&lt;/a&gt; was released, and things started getting more tangible.&lt;br /&gt;
So, at the beginning of 2023, I started poking the React team, and the maintainers of Apollo Client, TanStack React Query, and Redux got a meeting with the React team. The message was essentially “yeah , you can try to write an implementation now”. So we did.&lt;br /&gt;
A few weeks later, I tried out suspense hooks in the NextJs app router, because our users had asked for that, and everything broke. We had almost released something that would not work with the future of React, because we had been good ecosystem citizens and had written out code against the latest stable release of React. Nobody had told us that things might get hairy in Server Components. We now have a &lt;a href=&quot;https://github.com/apollographql/apollo-client-nextjs&quot;&gt;helper library&lt;/a&gt; in place, and Apollo Client works nicely with suspense and React Server Components, so there’s not too much harm done here. But it shows a clear disconnect in communication: we only knew that Suspense for data fetching on the client was delayed because the React team was “working on something” and didn’t want their hands bound by things released in the meantime that would lock them into one direction or the other. But we didn’t know it that “something” was Server Components, the React Forget compiler, or something else entirely.&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;highlighter-rouge&quot;&gt;use&lt;/code&gt; RFC also signals something else to me: The React team is trying to create a “symmetry” between Server and Client where it might not actually exist: The server renders once, and the client lives for a long time. A single promise might not be what you use on the client, because your data source might update repeatedly (in the case of a cache, think about updates from other components, requests, and optimistic updates). We need something more.&lt;/p&gt;

&lt;p&gt;What frustrates me most here, though, is that we could have given our userbase some kind of suspense implementation years ago, and made their lives much better - if the React team had communicated more openly what they are working on, and had given us guardrails to stay in-between. Even without &lt;code class=&quot;highlighter-rouge&quot;&gt;use&lt;/code&gt;, we could already have designed some interesting APIs. It would just not have been their “final form” yet.&lt;/p&gt;

&lt;h3 id=&quot;this-was-far-into-the-future-and-suddenly-became-very-urgent&quot;&gt;This was “far into the future”, and suddenly became very urgent&lt;/h3&gt;

&lt;p&gt;I am not joking when I say that one week before the App Router (and with that, React Server Components) were declared “stable”, I sincerely believed that we would have at least six more months, probably more like a year, until RSC would get the “stable” blessing from the React team.&lt;br /&gt;
At that point, I was already very familiar with React Server Components, and had implemented most of the Apollo Client RSC glue package - so it was not “under my radar”.&lt;br /&gt;
But in the past, these “big changes” like this were announced as “this is coming in about X months” by the React team, and instead of that, we were all playing with some kind of “unstable React build” without any indication that this would become stable anytime soon. Not an alpha, beta, or release candidate.&lt;br /&gt;
Then, within two days, Canary releases were declared stable, and the App Router was declared stable as well.&lt;br /&gt;
The part of the ecosystem that had been waiting for a bigger “starting sign” that something was getting ready was completely overwhelmed by these announcements. I was only prepared for it by sheer luck - because a bunch of users had asked for it.&lt;/p&gt;

&lt;h2 id=&quot;i-still-love-react-server-components&quot;&gt;I still love React Server Components&lt;/h2&gt;

&lt;p&gt;Despite all these complaints, I want to repeat this paragraph. I am extemely frustrated. But I also see a ton of promise in React Server Components.&lt;br /&gt;
There is just a ton of work to be done for all of us.&lt;/p&gt;

&lt;h2 id=&quot;i-also-have-some-suggestions&quot;&gt;I also have some suggestions&lt;/h2&gt;

&lt;p&gt;And that brings us to the part where I stop ranting and start making suggestions. And before I get to the suggestions: If I suggest a new API here, I would be happy to try and implement one or more of these features if the React of Next.js team communicate that they are interested in actually adopting them in the end!&lt;/p&gt;

&lt;h3 id=&quot;hide-experimental-things-in-canaries&quot;&gt;Hide experimental things in Canaries&lt;/h3&gt;

&lt;p&gt;This is the most obvious win right now: I know that Canaries contain React code with experimental features. The problem is that these Canaries are shipped as part of “stable” Frameworks. As a result, users get exposed to these experimental features, might accidentally start using them, and have things breaking in the future. This is extra sneaky in the case of &lt;code class=&quot;highlighter-rouge&quot;&gt;async&lt;/code&gt; functions: in the past, this would have provoked an error from React, and now in some canaries it just works, and in others you see an infinite loop.&lt;br /&gt;
I know it might not always be feasible, but can we get feature flags to hide these features in Canary builds here? Throwing errors if a user accidentally uses an unstable feature would really help a lot!&lt;/p&gt;

&lt;p&gt;(Much has been said about documentation what actually is in these Canaries, and I believe it already has been heard loudly at this point, so I’ll skip that suggestion here.)&lt;/p&gt;

&lt;h3 id=&quot;trying-to-get-the-client-and-server-user-experience-in-symmetry&quot;&gt;Trying to get the client and server user experience in symmetry&lt;/h3&gt;

&lt;p&gt;Right now, a lot of concepts don’t translate well between RSC and CC (Client Components), and as a result, we have to give our users very different APIs for both of these environments.&lt;br /&gt;
I don’t think that’s necessary. With a few more primitives/conventions, we can create APIs that (apart from initialization) are used the exact same way between RSC and CC.&lt;br /&gt;
I believe this would help both adoption, and users switching between projects that are RSC-capable and those that are not.&lt;/p&gt;

&lt;p&gt;Of course, I’m speaking from the point of a “data fetching library” here, but I think a lot of these points also apply to other libraries.&lt;/p&gt;

&lt;h4 id=&quot;familiar-client-patterns-on-the-server&quot;&gt;Familiar client patterns on the server&lt;/h4&gt;

&lt;p&gt;Expected usage on Client and Server:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;MyComponent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;useQueryWithSuspense&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;query&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;h2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/h2&amp;gt;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Theoretically, it should be possible to offer this API in both environments. It would be a nice “symmetrical” API, moving a CC pattern into RSC.&lt;/p&gt;

&lt;h5 id=&quot;the-missing-pattern&quot;&gt;The missing pattern&lt;/h5&gt;

&lt;p&gt;Unfortunately, there is a missing link for this: in a RSC, &lt;code class=&quot;highlighter-rouge&quot;&gt;useQueryWithSuspense&lt;/code&gt; doesn’t have access to Context, and cannot get a user-defined client. This could almost be made to work with something like&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;getClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;registerClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;makeClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;getClient&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;React&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;cache&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;makeClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;but there is no good way right now to ensure that the user code that calls &lt;code class=&quot;highlighter-rouge&quot;&gt;registerClient&lt;/code&gt; is actually called, apart from littering it into all layouts and pages. There is no central entry point file in Server Components.
&lt;strong&gt;It would be great if frameworks could offer a “&lt;code class=&quot;highlighter-rouge&quot;&gt;bootstrap&lt;/code&gt;” entrypoint that would be executed every time before a server component renders.&lt;/strong&gt;
This is probably only a little tweak to Next.js &amp;amp; co, but would allow us to write this kind of symmetrical API.&lt;/p&gt;

&lt;h4 id=&quot;server-patterns-on-the-client&quot;&gt;“Server patterns” on the client.&lt;/h4&gt;

&lt;p&gt;This is more of a “server pattern” that would be great on the client:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;MyComponent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;maxPage&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}){&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;readQuery&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;useEndpoint&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;pages&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;maxPage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fill&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;undefined&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;pageNr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;readQuery&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pageNr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pages&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pagePromise&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;page&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;use&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pagePromise&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;})}&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This one is possible on the server, and it is kinda possible in the browser, with a lot of workarounds, but one gaping problem: In the browser, our component lives for a long time, and a data source might update externally, at a later point in time.
Now, it could be solved as an implementation detail of &lt;code class=&quot;highlighter-rouge&quot;&gt;useEndpoint&lt;/code&gt; to, in that case, swap out a promise in local state against a resolved one, and return that instead - but that would always force a rerender of &lt;code class=&quot;highlighter-rouge&quot;&gt;MyComponent&lt;/code&gt;. In this example, that’s okay, but these &lt;code class=&quot;highlighter-rouge&quot;&gt;pagePromise&lt;/code&gt; instances could also have been passed down to child components and only be &lt;code class=&quot;highlighter-rouge&quot;&gt;use&lt;/code&gt;d there. Currently, this would always cause an unneccessary rerender of the parent component, because we have to swap out those promises during a rerender.&lt;/p&gt;

&lt;h5 id=&quot;the-missing-api&quot;&gt;The missing API&lt;/h5&gt;

&lt;p&gt;&lt;strong&gt;If we could &lt;code class=&quot;highlighter-rouge&quot;&gt;use(observable)&lt;/code&gt; instead, we would not have this problem.&lt;/strong&gt; So this is (not for the first time) my plea to give us this API.
The server doesn’t need this - RSCs render once, and then everything is thrown away. But in the browser, components live for a long time, and they won’t need data from a promise only once. There will be updates.&lt;/p&gt;

&lt;h3 id=&quot;shipping-features-that-are-a-pain-or-impossible-to-solve-from-a-library-or-even-framework-perspective&quot;&gt;Shipping features that are a pain (or impossible) to solve from a library, or even framework perspective&lt;/h3&gt;

&lt;h4 id=&quot;in-rscstreaming-ssr-usestream&quot;&gt;(in RSC/Streaming SSR) useStream&lt;/h4&gt;

&lt;p&gt;I’m just going to point at &lt;a href=&quot;https://github.com/reactjs/rfcs/pull/219&quot;&gt;the RFC for &lt;code class=&quot;highlighter-rouge&quot;&gt;useStream&lt;/code&gt;&lt;/a&gt; here. We really need this, as the current workarounds will differ from framework to framework and, at least with Next.js, also have very unfortunate timing. Only being able to inject data into the stream when a suspense boundary finishes can be far too late and lead to very problematic race conditions between Server and Browser.&lt;br /&gt;
This API is most vital in streaming SSR and less important in RSCs, but it might be a good idea to offer it there, too.&lt;/p&gt;

&lt;h4 id=&quot;in-rscstreaming-ssr-registercleanuphandler&quot;&gt;(in RSC/Streaming SSR) registerCleanupHandler&lt;/h4&gt;

&lt;p&gt;This goes hand-in-hand with &lt;code class=&quot;highlighter-rouge&quot;&gt;useStream&lt;/code&gt;.&lt;br /&gt;
It would be great to register a handler to be called after the last component has finished rendering, shortly before the stream is closed, to execute some cleanup logic and inject one last bunch of data into the stream.&lt;br /&gt;
Not having this means that on the server, connections could stay open (e.g. when receiving streamed data), receiving data that will not be accessible on the client anymore, and the client might not be aware that the server already stopped streaming, and still wait for that data instead of making a request on it’s own.
This API would be equally useful in RSCs and streaming SSR.&lt;/p&gt;

&lt;h4 id=&quot;in-client-components-usecomponentidentifierteardownfn&quot;&gt;(in Client Components) useComponentIdentifier(teardownFn?)&lt;/h4&gt;

&lt;p&gt;There was recently a great &lt;a href=&quot;https://twitter.com/statisticsftw/status/1669400359192653824&quot;&gt;talk by Robert Balicki&lt;/a&gt; (&lt;a href=&quot;https://docs.google.com/presentation/d/1V48wk33IQtWtDG-4z560vpn-i73oDpK8WdzZu770Nn4/edit#slide=id.p&quot;&gt;slides&lt;/a&gt; &lt;a href=&quot;https://www.youtube.com/live/Hwly0_kBU2I?feature=share&amp;amp;t=4165&quot;&gt;video&lt;/a&gt;) that shows how much is necessary to get Suspense for data fetching working on the client. Components render, they suspend, they render again without knowing that they rendered before. As a result, there is an absurd dance that every library has to do in userspace to ensure that a (hopefully stable) promise is returned, and that data that is not needed anymore (because a component didn’t render in the end, or changed props in the meantime and requested different data) is disposed of correctly. We are talking reference counting, timers, all that jazz. React knows what the last promise for a component was when it restarts a component render, so it has some concept of component identity, even if a component didn’t commit yet.&lt;br /&gt;
It would save a ton of userspace workarounds (and, again, there is no good way to do this at all) if React would allow a component to ask for some kind of unique identifier. That could even just be an empty object to be used as a key in a Map or WeakMap.
Bonus points if we could get some kind of “final teardown” callback to do a nice cleanup once a component is discarded.&lt;/p&gt;

&lt;h2 id=&quot;and-now&quot;&gt;And now?&lt;/h2&gt;

&lt;p&gt;Honestly, I don’t know. I could open RFCs for these features that I think are still missing, but I already wrote under the &lt;code class=&quot;highlighter-rouge&quot;&gt;useStream&lt;/code&gt; RFC that we really need something like this and even offered to implement it. There was no feedback to it, so I am not too hopeful that opening more RFCs or Issues in the Next.js GitHub Issues (that currently seem to be drowning in confused users and/or bugs) will lead to anything.&lt;br /&gt;
So instead, I’m writing this post. And I hope the right person sees it because the Twitter or Reddit algorithm sweeps it their way.&lt;br /&gt;
I’m open to talk about these ideas and want to help if I can. Please talk to me!&lt;/p&gt;
</description>
        <pubDate>Wed, 05 Jul 2023 00:00:00 +0000</pubDate>
        <link>https://www.phryneas.de/react-server-components-controversy</link>
        <guid isPermaLink="true">https://www.phryneas.de/react-server-components-controversy</guid>
        
        
      </item>
    
      <item>
        <title>Talks &amp; Slides for React Summit 2023 - GraphQL in 2023 - Still Relevant?</title>
        <description>&lt;p&gt;A remote talk I gave together with my teammate Jerel Miller at React Summit Amsterdam.&lt;/p&gt;

&lt;h2 id=&quot;graphql-in-2023---still-relevant&quot;&gt;GraphQL in 2023 - Still Relevant?&lt;/h2&gt;
&lt;details class=&quot;abstract&quot;&gt;
&lt;summary&gt;
Abstract (click to expand)
&lt;/summary&gt;
&lt;cite&gt;&lt;div&gt;
      &lt;p&gt;With fetching libraries like TanStack Query, swr, or RTK Query becoming more widespread, some of the immediate “selling points” of GraphQL clients seem to be less unique - so it might be a good idea to take a step back and ask the question “is this even still relevant?”.&lt;br /&gt;
And to already take the answer away - it is “yes”.&lt;br /&gt;
The unique selling points of GraphQL go far beyond having a smooth data fetching experience by solving many inter-team and architectural problems.&lt;br /&gt;
While it might not always be immediately evident as a benefit for us as Frontend Developers,  GraphQL gives us a lot of freedom and makes us less dependent on backend teams implementing a Backend-for-the-frontend for us.&lt;br /&gt;
Also, while data-fetching libraries have made it a lot easier to work with REST nowadays, GraphQL still has properties that are just not present in traditional REST APIs, and on top of that GraphQL has kept evolving.&lt;br /&gt;
New directives like @live or @defer enable developers to create a fantastic user experience with very little work - especially when combined with React’s new suspense features.&lt;/p&gt;
    &lt;/div&gt;&lt;/cite&gt;
&lt;/details&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://drive.google.com/file/d/1dw3NN0Z9ZmVJ488H8aMvkMhCgT5WSkE4/view?usp=sharing&quot;&gt;Slides&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://gitnation.com/contents/graphql-in-2023-still-relevant&quot;&gt;Video&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Tue, 06 Jun 2023 00:00:00 +0000</pubDate>
        <link>https://www.phryneas.de/react_summit-amsterdam-2023-talk</link>
        <guid isPermaLink="true">https://www.phryneas.de/react_summit-amsterdam-2023-talk</guid>
        
        
      </item>
    
      <item>
        <title>Talks &amp; Slides for c't webdev 2022 - Redux im Jahr 2022 — alles anders?</title>
        <description>&lt;p&gt;This was a live coding talk I gave at c’t webdev in Cologne in German.&lt;/p&gt;

&lt;h2 lang=&quot;de&quot;&gt;Redux im Jahr 2022 — alles anders?&lt;/h2&gt;
&lt;details class=&quot;abstract&quot;&gt;
&lt;summary&gt;
Abstract (click to expand)
&lt;/summary&gt;
&lt;cite&gt;&lt;div lang=&quot;de&quot;&gt;
      &lt;p&gt;Wenn man an Redux denkt, hat man oft erst Mal sehr viel “rituellen” Code vor dem inneren Auge. ACTION_TYPE Konstanten, immutable Logik in switch..case reducern mit tief verschachtelten Spread-Operatoren, handgeschriebene “Action Creator” Funktionen und arkanes Store-Setup — all das am besten verteilt auf dutzende Dateien in der ganzen Codebasis.&lt;/p&gt;

      &lt;p&gt;Nichts könnte von moderenem Redux weiter entfernt sein — denn Redux hat sich in den letzten Jahren massiv verändert — die benötigte Boilerplate wurde stark entschlackt und moderner Code ist noch etwa ein Viertel dessen, was man früher geschrieben hätte — und Code für Api-Interaktionen wird sogar mittels RTK Query auf wenige Zeilen je Endpunkt reduziert. Insbesondere zwischen alter und neuer Nutzung mit TypeScript liegen welten.&lt;/p&gt;

      &lt;p&gt;Leider ist diese Veränderung in weiten Teilen der Community unbemerkt geblieben — zu viele Kurse und Tutorials wurden niemals geupdated und werden immer noch massenweise gelesen.&lt;/p&gt;

      &lt;p&gt;In diesem Talk stellt ein Maintainer der Bibliothek “legacy Redux” neben “modernes Redux”, zeigt auf, was sich geändert hat, was man heutzutage nicht mehr braucht und welche neuen Apis dazu gekommen sind.&lt;/p&gt;
    &lt;/div&gt;&lt;/cite&gt;
&lt;/details&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/phryneas/ct_webdev_redux_2022&quot;&gt;Talk Repository&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Tue, 08 Nov 2022 00:00:00 +0000</pubDate>
        <link>https://www.phryneas.de/ct_webdev-2022-talk</link>
        <guid isPermaLink="true">https://www.phryneas.de/ct_webdev-2022-talk</guid>
        
        
      </item>
    
      <item>
        <title>Talks &amp; Slides for React Advanced London 2022 - Dealing with ADHD as a Developer</title>
        <description>&lt;p&gt;This was a remote talk I gave at React Advanced London in 2022.&lt;/p&gt;

&lt;h2 id=&quot;dealing-with-adhd-as-a-developer&quot;&gt;Dealing with ADHD as a Developer&lt;/h2&gt;
&lt;details class=&quot;abstract&quot;&gt;
&lt;summary&gt;
Abstract (click to expand)
&lt;/summary&gt;
&lt;cite&gt;&lt;div&gt;

      &lt;p&gt;“Hi, my name is Lenz and two years ago I was diagnosed with ADHD (attention deficit hyperactivity disorder).” Well, this is not going to be a self-help-group, but I think it is important to talk about this wildly underrepresented topic.&lt;/p&gt;

      &lt;p&gt;Since my diagnosis, I have spent a lot of time talking to other developers about it - and many of them also have ADHD, often a late diagnosis. It seems that we are quite the vulnerable population - or rather, it seems like a lot of ADHD people are drawn towards a developer job.&lt;/p&gt;

      &lt;p&gt;In this talk, I want to tell you about myself, how ADHD affected me and how the late diagnosis changed my life. But it didn’t only change my life - it also affected everyone around me. As colleagues, we have found a new level of understanding with each other that helped us more than any team-building event. And in the end, made us more productive since we now know how to better use our individual strengths, instead of trying to meet social expectations.&lt;/p&gt;

      &lt;p&gt;I will also talk about general ADHD symptoms and try to give you a rough overview on the topic - what kinds of treatments exist, what kind of coping strategies there are and where the line between “everybody is a bit forgetful” and “ADHD is an illness” lies.&lt;/p&gt;

      &lt;p&gt;You might recognize yourself in this. Or just a close friend or colleague. Either way, this talk will give you awareness &amp;amp; insights how the mind of a neurodivergent person can work differently - or it may even be an important wake-up-call.&lt;/p&gt;

      &lt;p&gt;Disclaimer: while I have an interest in the topic and am personally affected, I am not a trained professional on the topic and everything you hear here can only be an inspiration, but never medical advice.&lt;/p&gt;
    &lt;/div&gt;&lt;/cite&gt;
&lt;/details&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://gitnation.com/contents/dealing-with-adhd-as-a-developer&quot;&gt;Video&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Mon, 24 Oct 2022 00:00:00 +0000</pubDate>
        <link>https://www.phryneas.de/react_advanced-london-2022-talk</link>
        <guid isPermaLink="true">https://www.phryneas.de/react_advanced-london-2022-talk</guid>
        
        
      </item>
    
      <item>
        <title>Do not create union types with Redux Action Types. It's most likely an antipattern.</title>
        <description>&lt;p&gt;So, there is a long-standing TypeScript &amp;amp; Redux pattern of creating a union &lt;code class=&quot;highlighter-rouge&quot;&gt;RootAction&lt;/code&gt; type that contains all your application’s action types. Sometimes, you would also create a lot of reducer-specific sub-unions.&lt;br /&gt;
I think that this has always been a crutch - and given the options we have today, it’s most likely an antipattern.&lt;br /&gt;
So let’s look at why it was used, where it was used and what you can use instead.&lt;/p&gt;

&lt;!--snip--&gt;

&lt;h2 id=&quot;why-was-it-used-a-look-at-typed-reducers&quot;&gt;Why was it used? A look at typed Reducers.&lt;/h2&gt;

&lt;p&gt;Classically, these action union types were created to use the &lt;a href=&quot;https://www.typescriptlang.org/docs/handbook/unions-and-intersections.html#discriminating-unions&quot;&gt;Discriminating Union&lt;/a&gt; pattern.&lt;/p&gt;

&lt;p&gt;This allowed you to do something like write a reducer like&lt;/p&gt;

&lt;div class=&quot;language-ts highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;actionType1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;actionType2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ActionA&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;typeof&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;actionType1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ActionB&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;typeof&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;actionType2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;State&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{};&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Actions&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ActionA&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ActionB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;reducer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;State&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Actions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;State&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;actionType1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;cm&quot;&gt;/* action.payload.value is inferred correctly here */&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;state&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;actionType2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;cm&quot;&gt;/* action.payload.value is inferred correctly here */&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;state&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In a world where &lt;code class=&quot;highlighter-rouge&quot;&gt;switch&lt;/code&gt;…&lt;code class=&quot;highlighter-rouge&quot;&gt;case&lt;/code&gt; reducers were the norm anyways, this seemed like a very handy pattern. It required a little extra work, like collecting all actions together in a central place and defining all those &lt;code class=&quot;highlighter-rouge&quot;&gt;type&lt;/code&gt; constants, but those &lt;code class=&quot;highlighter-rouge&quot;&gt;type&lt;/code&gt; constants were already defined anyways and due to all that boilerplate, building an extra union type didn’t seem so bad.&lt;/p&gt;

&lt;h3 id=&quot;it-all-starts-with-a-lie-to-the-compiler&quot;&gt;It all starts with a lie to the compiler.&lt;/h3&gt;

&lt;p&gt;There is a point about the discriminated union pattern that was missed though: A discriminated union has to be complete for it to work. Otherwise, you will hide errors.&lt;br /&gt;
In this specific case, it starts with a lie to the compiler: we’re telling &lt;code class=&quot;highlighter-rouge&quot;&gt;tsc&lt;/code&gt; that this reducer function will only ever be called with an action that is a member of the &lt;code class=&quot;highlighter-rouge&quot;&gt;Actions&lt;/code&gt; union.&lt;br /&gt;
But is it really? No, this reducer will be called by every action that is ever being dispatched in our application. So if we were only combining the action types we cared about, we’d already be lost. But what if we really went thorougly through the whole app, putting every single action type into that union?&lt;br /&gt;
It would still be incomplete.&lt;br /&gt;
Your application is not the only source of actions.&lt;br /&gt;
There’s also middleware, popular examples being “connected-react-router” which for example dispatched a &lt;code class=&quot;highlighter-rouge&quot;&gt;'@@router/LOCATION_CHANGE'&lt;/code&gt;-typed action or redux-persist, which will dispatch a &lt;code class=&quot;highlighter-rouge&quot;&gt;'persist/REHYDRATE'&lt;/code&gt;-typed action.&lt;br /&gt;
And even if you went through all middlewares and also added their action types to the union, you’d still be missing the redux-internal &lt;code class=&quot;highlighter-rouge&quot;&gt;'INIT'&lt;/code&gt; action. Well, let’s just add that. Want to know a fun fact about &lt;code class=&quot;highlighter-rouge&quot;&gt;INIT&lt;/code&gt;? In development mode, that action name is &lt;strong&gt;randomized&lt;/strong&gt; to prevent developers from relying on that redux internal.&lt;br /&gt;
Bottom line? &lt;strong&gt;Your &lt;code class=&quot;highlighter-rouge&quot;&gt;Actions&lt;/code&gt; type will never be complete, no matter how hard you try.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So having accepted that, we’ll probably do what most people (&lt;a href=&quot;https://redux.js.org/recipes/usage-with-typescript#type-checking-reducers&quot;&gt;and, at this time, even the redux documentation on TypeScript&lt;/a&gt;) do and just create smaller sub-types, one small union for all actions we want to handle in a specific reducer. So, like in our example above, that type might even only contain two action types. Let’s assume it does.&lt;/p&gt;

&lt;p&gt;What bugs are actually hidden by that little oversimplification?&lt;/p&gt;

&lt;h4 id=&quot;missing-return-statement&quot;&gt;Missing return statement&lt;/h4&gt;

&lt;p&gt;Let’s take our reducer from above and just remove that last return statement.&lt;/p&gt;

&lt;div class=&quot;language-diff highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;function reducer(state: State, action: Actions): State {
&lt;/span&gt;  switch (action.type) {
    case actionType1:
      return { ...state, /* action.prop1 is inferred correctly here */ }
    case actionType2:
      return { ...state, /* action.prop2 is inferred correctly here */ }
  }
&lt;span class=&quot;gd&quot;&gt;-  return state;
&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This is definitely a bug. This reducer will now return &lt;code class=&quot;highlighter-rouge&quot;&gt;undefined&lt;/code&gt; in case of that &lt;code class=&quot;highlighter-rouge&quot;&gt;INIT&lt;/code&gt; action we discussed above. But TypeScript won’t notice. TypeScript assumes that this method will only ever be called with one of two action types - and both of these are handled. Because we are working on what seems (but really is not) a discriminated union here, &lt;a href=&quot;https://www.typescriptlang.org/docs/handbook/unions-and-intersections.html#union-exhaustiveness-checking&quot;&gt;union exhaustiveness checking&lt;/a&gt; kicks in and assumes that there will never any other return path and that this function will always return a &lt;code class=&quot;highlighter-rouge&quot;&gt;State&lt;/code&gt; object.&lt;/p&gt;

&lt;p&gt;Which it obviously does not.&lt;/p&gt;

&lt;h4 id=&quot;action-shape-might-not-be-what-it-seems-to-be&quot;&gt;Action shape might not be what it seems to be.&lt;/h4&gt;

&lt;p&gt;Also, did you notice that all actions in our union have a &lt;code class=&quot;highlighter-rouge&quot;&gt;action.payload.value&lt;/code&gt; property? TypeScript will now allow us to directly access that property without any additional checks - after all, it will always be there - surely this method won’t be called with any other action.&lt;br /&gt;
Except for a lot of other actions. And at least that &lt;code class=&quot;highlighter-rouge&quot;&gt;INIT&lt;/code&gt; type has no &lt;code class=&quot;highlighter-rouge&quot;&gt;payload&lt;/code&gt; property, so we’re just one execution of our app away from the runtime error message&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Uncaught TypeError: action.payload is undefined&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&quot;a-lie-to-the-compiler-is-a-lie-to-your-team-and-your-future-self&quot;&gt;A lie to the compiler is a lie to your team and your future self&lt;/h3&gt;

&lt;p&gt;Of course, all that doesn’t seem too bad. You’ll surely remember that you lied there and take all possible precautions that none of those above bugs happen. But will you really, a year or two down the line? Will a new team member that’s just getting onboarded and is not used to your little redux-lies yet?&lt;br /&gt;
You’re deliberately disabling TypeScript there, but it is not visible to anyone who doesn’t know &lt;em&gt;the pattern&lt;/em&gt;. If you were &lt;code class=&quot;highlighter-rouge&quot;&gt;any&lt;/code&gt;-casting, at least that would be visible. Here it’s not. Don’t do that if there are other ways to do the same.&lt;/p&gt;

&lt;p&gt;But are there?&lt;/p&gt;

&lt;h3 id=&quot;what-to-do-instead&quot;&gt;What to do instead?&lt;/h3&gt;

&lt;p&gt;The correct tool for this use case has been around for a long type: &lt;a href=&quot;https://www.typescriptlang.org/docs/handbook/advanced-types.html#user-defined-type-guards&quot;&gt;Type predicate functions&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A naive variation of a type guard function would look like this:&lt;/p&gt;

&lt;div class=&quot;language-ts highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;AnyAction&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;redux&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kr&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;SpecificAction&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;AnyAction&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;somethingSpecific&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;matchSpecificAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;AnyAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;SpecificAction&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;somethingSpecific&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;doSomething&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;AnyAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;matchSpecificAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// this is correctly inferred to `string` here&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Of course, this does seem to be a lot of code when writing it by hand - but it can be automated. And it can be automated a lot better than manually having to combine action types.&lt;/p&gt;

&lt;p&gt;If you are using redux toolkit, all your action creators created by &lt;code class=&quot;highlighter-rouge&quot;&gt;createAction&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;createSlice&lt;/code&gt; will already have such a type guard:&lt;/p&gt;

&lt;div class=&quot;language-ts highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;createAction&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;@reduxjs/toolkit&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;AnyAction&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;redux&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;myAction&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;createAction&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;my/action&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;doSomething&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;AnyAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;myAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// this is correctly inferred to `string` here&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;and if you are not using redux toolkit, you could for example use this helper function that attaches a &lt;code class=&quot;highlighter-rouge&quot;&gt;.match(action)&lt;/code&gt; function and a &lt;code class=&quot;highlighter-rouge&quot;&gt;.type&lt;/code&gt; property to every action creator you pass into it:&lt;/p&gt;

&lt;div class=&quot;language-ts highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;AnyAction&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;redux&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Matchable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;AC&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;AnyAction&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;AC&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ReturnType&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;AC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;AnyAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ReturnType&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;AC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;withMatcher&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;AC&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;AnyAction&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;actionCreator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;AC&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Matchable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;AC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;withMatcher&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;AC&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(...&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[])&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;AnyAction&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;actionCreator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;AC&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Matchable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;AC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;withMatcher&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;AC&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(...&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[])&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;AnyAction&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;actionCreator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;AC&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ReturnType&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;AC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Matchable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;AC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;withMatcher&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;actionCreator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Function&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;_type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;string&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_type&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;actionCreator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;actionCreator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;assign&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;actionCreator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;AnyAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now you can just wrap your action creator in &lt;code class=&quot;highlighter-rouge&quot;&gt;withMatcher&lt;/code&gt; and use it like in the example above!&lt;/p&gt;

&lt;div class=&quot;language-ts highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;createActionA&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;withMatcher&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;foo/bar&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Why the additional &lt;code class=&quot;highlighter-rouge&quot;&gt;type&lt;/code&gt; you ask? That might come in handy when we talk about &lt;code class=&quot;highlighter-rouge&quot;&gt;redux-saga&lt;/code&gt; later ;)&lt;/p&gt;

&lt;p&gt;With all this, your &lt;code class=&quot;highlighter-rouge&quot;&gt;Reducer&amp;lt;MyState, MyActions&amp;gt;&lt;/code&gt; lie to the compiler becomes a valid &lt;code class=&quot;highlighter-rouge&quot;&gt;Reducer&amp;lt;State, AnyAction&amp;gt;&lt;/code&gt; and will probably look something like this:&lt;/p&gt;

&lt;div class=&quot;language-ts highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;reducer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;MyState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;AnyAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;MyState&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;specificAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;state&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* action is correctly inferred here */&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;anotherAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;state&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* action is correctly inferred here */&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The bugs from above? Don’t apply any more.&lt;/p&gt;

&lt;p&gt;Of course, you can reduce that down quite a bit using &lt;code class=&quot;highlighter-rouge&quot;&gt;createReducer&lt;/code&gt; or &lt;code class=&quot;highlighter-rouge&quot;&gt;createSlice&lt;/code&gt; from &lt;a href=&quot;https://redux-toolkit.js.org/&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;@reduxjs/toolkit&lt;/code&gt;&lt;/a&gt;, which is the official recommendation and which you really should be using.&lt;/p&gt;

&lt;p&gt;With &lt;code class=&quot;highlighter-rouge&quot;&gt;createSlice&lt;/code&gt;, it would look like this:&lt;/p&gt;

&lt;div class=&quot;language-ts highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;slice&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;createSlice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;counter&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;initialState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;reducer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// will result in an action of type `counter/increment`&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;increment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;// state values can be modified mutably thanks to `immer` integration&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;incrementBy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;payload&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;PayloadAction&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// automatically generated action creators with correct types&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;increment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;incrementBy&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;slice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;actions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;slice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;reducer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;No matter what you use, your reducers should be covered now. No more lie to the compiler, no more collection type definitions over multiple files in a central location and creating unwieldy unions.&lt;/p&gt;

&lt;h2 id=&quot;where-was-it-used-as-wellwhat-to-use-instead&quot;&gt;Where was it used as well/what to use instead?&lt;/h2&gt;

&lt;p&gt;Of course, that union type was used in several patterns with other libraries &amp;amp; use cases as well. Let’s look at them!&lt;/p&gt;

&lt;h3 id=&quot;redux-observables&quot;&gt;Redux Observables&lt;/h3&gt;

&lt;p&gt;Before:&lt;/p&gt;

&lt;div class=&quot;language-ts highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;epic&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;actions$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Observable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;MyActions&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;actions$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;ofType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;INCREMENT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;// action is correctly typed here&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;After&lt;/p&gt;

&lt;div class=&quot;language-ts highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;epic&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;actions$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Observable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;AnyAction&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;actions$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;increment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;// action is correctly typed here&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;So we are just moving from the special case &lt;code class=&quot;highlighter-rouge&quot;&gt;ofType&lt;/code&gt; that tried to pull it’s own “discriminating union” over the observable action type to the more general &lt;code class=&quot;highlighter-rouge&quot;&gt;filter&lt;/code&gt; method that just accepts any type guard function.&lt;/p&gt;

&lt;h3 id=&quot;redux-saga&quot;&gt;Redux Saga&lt;/h3&gt;

&lt;p&gt;Redux saga already works out-of-the box with action creators that have a &lt;code class=&quot;highlighter-rouge&quot;&gt;.type&lt;/code&gt; property for effects like &lt;code class=&quot;highlighter-rouge&quot;&gt;take&lt;/code&gt; with another saga as the second argument. So using both redux toolkit action creators as well as the &lt;code class=&quot;highlighter-rouge&quot;&gt;withMatcher&lt;/code&gt;-created action creators from above will work just fine without any further modifications.&lt;/p&gt;

&lt;p&gt;But, generally &lt;code class=&quot;highlighter-rouge&quot;&gt;redux-saga&lt;/code&gt; with TypeScript is a bit of a pain: the result of a &lt;code class=&quot;highlighter-rouge&quot;&gt;yield&lt;/code&gt; is just never defined, so you still need the types around for manual casting:&lt;/p&gt;

&lt;div class=&quot;language-ts highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;take&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;redux-saga/effects&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;exampleSaga&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// cannot be inferred and needs to be manually typed&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;IncrementActionType&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;take&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;slice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;actions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;incrementBy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;But… did you know that there is a library called &lt;code class=&quot;highlighter-rouge&quot;&gt;typed-redux-saga&lt;/code&gt;?&lt;/p&gt;

&lt;div class=&quot;language-ts highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;take&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;typed-redux-saga&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;exampleSaga&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// correctly inferred as { payload: number; type: string; }&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;take&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;slice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;actions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;incrementBy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It slightly changes the semantics of yielding effects: instead of &lt;code class=&quot;highlighter-rouge&quot;&gt;yield&lt;/code&gt;, you are now using &lt;code class=&quot;highlighter-rouge&quot;&gt;yield*&lt;/code&gt;. But apart from that, everything is the same. And it just works, with type inference at every corner!&lt;/p&gt;

&lt;h3 id=&quot;custom-middleware&quot;&gt;Custom Middleware&lt;/h3&gt;

&lt;p&gt;Custom middleware works just like the reducer example above: &lt;code class=&quot;highlighter-rouge&quot;&gt;switch ... case&lt;/code&gt; becomes &lt;code class=&quot;highlighter-rouge&quot;&gt;if ... else&lt;/code&gt; with type guards. Nothing to worry about here.&lt;/p&gt;

&lt;h3 id=&quot;dispatch&quot;&gt;Dispatch&lt;/h3&gt;

&lt;p&gt;Now, all that said, there is one last valid-ish use for an application-wide &lt;code class=&quot;highlighter-rouge&quot;&gt;MyActions&lt;/code&gt; type: Some people want to prevent wrongly typed actions to be passed into &lt;code class=&quot;highlighter-rouge&quot;&gt;dispatch&lt;/code&gt;. Yes, I get you.
But also: Are you serious? You are going around and hand-writing actions in the first place?&lt;br /&gt;
My solution: make it a rule in your team to always use action creators. Those will also be typed correctly and work as an equally good solution.
All without going through the work of manually gathering all your action types in one place.&lt;/p&gt;

&lt;p&gt;By the way: If someone were to write an eslint rule for that, we’d probably be very happy to ship that with redux toolkit as a recommendation ;)&lt;/p&gt;
</description>
        <pubDate>Sat, 28 Nov 2020 00:00:00 +0000</pubDate>
        <link>https://www.phryneas.de/redux-typescript-no-discriminating-union</link>
        <guid isPermaLink="true">https://www.phryneas.de/redux-typescript-no-discriminating-union</guid>
        
        
      </item>
    
      <item>
        <title>Talks &amp; Slides for the iJS Munich 2019 - reducing global React state and TypeScript for React developers</title>
        <description>&lt;p&gt;This fall, I did two talks on the international JavaScript Conference in Munich. One talk was about avoiding global state in React applications (in German), the other talk was an introduction to TypeScript for React developers.&lt;/p&gt;

&lt;h2 lang=&quot;de&quot;&gt;
Warum Global State keine eierlegende Wollmilchsau ist – und was wir wirklich nutzen sollten (German)
&lt;/h2&gt;

&lt;details class=&quot;abstract&quot;&gt;
&lt;summary&gt;
Abstract (click to expand)
&lt;/summary&gt;
&lt;cite&gt;&lt;div lang=&quot;de&quot;&gt;
      &lt;p&gt;In vielen React-Applikationen hat sich der Trend etabliert, die Global-State-Managementlösung (meist Redux oder MobX) zu verwenden – als Allheilmittel für alles, was auch nur im entferntesten mit State zu tun hat. Aber während der Gedanke insbesondere angesichts unzähliger Tutorials naheliegt: irgendwie fühlt es sich meist unhandlich an. Außerdem arbeiten wir damit “an React vorbei” und machen oft genug React-interne Performanceoptimierungen kaputt.&lt;/p&gt;

      &lt;p&gt;Zum Glück gibt es für viele Anwendungsfälle inzwischen bessere Lösungen, mit denen wir den Herausforderungen einer modernen React-Applikation beikommen können – am Ende bleibt ein globaler State, den man auch guten Gewissens so nennen kann.&lt;/p&gt;

      &lt;p&gt;Der Talk stellt verschiedene Arten von State in einer modernen React-Applikation vor und analysiert, welche Spielweisen besser nicht in den globalen State gehören (natürlich auch: wohin denn dann?). Beispiele, wo der globaler State weiterhin eine wichtige Rolle spielt und wie wir ihn klüger nützen können, runden den Vortrag ab.&lt;/p&gt;

    &lt;/div&gt;&lt;/cite&gt;
&lt;/details&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://phryneas.github.io/talk-ijs_munich-react-global-state_2019-de/&quot;&gt;Slides&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/phryneas/talk-ijs_munich-react-global-state_2019-de&quot;&gt;Code examples&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;typescript-for-react-developers&quot;&gt;TypeScript for React developers&lt;/h2&gt;

&lt;details class=&quot;abstract&quot;&gt;
&lt;summary&gt;
Abstract (click to expand)
&lt;/summary&gt;
&lt;cite&gt;&lt;div&gt;
      &lt;p&gt;TypeScript adds static typing to JavaScript – and you can use it when developing applications with React. I will introduce you to the basic concepts of static typing and will show you how to use TypeScript with React. We are going to discuss not only the benefits but also the downsides of this approach. I will also show you how you can benefit from TypeScript when using state management libraries such as Redux.&lt;/p&gt;

      &lt;p&gt;&lt;em&gt;Abstract by Hans-Christian Otto, who I filled in for with this talk.&lt;/em&gt;&lt;/p&gt;

    &lt;/div&gt;&lt;/cite&gt;
&lt;/details&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=8NATZa6mhh4&quot;&gt;Video&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Wed, 23 Oct 2019 00:00:00 +0000</pubDate>
        <link>https://www.phryneas.de/ijs-munich-2019-talks</link>
        <guid isPermaLink="true">https://www.phryneas.de/ijs-munich-2019-talks</guid>
        
        
      </item>
    
      <item>
        <title>Talks &amp; Slides for the iJS London 2019 - The State of React’s State in 2019</title>
        <description>&lt;p&gt;I was over in London to talk about the state of React’s State handling ecosystem in 2019, comparing plain Context, Redux, MobX, MobX State Tree and local State with Apollo.&lt;/p&gt;

&lt;h2 id=&quot;the-state-of-reacts-state-in-2019&quot;&gt;The State of React’s State in 2019&lt;/h2&gt;
&lt;details class=&quot;abstract&quot;&gt;
&lt;summary&gt;
Abstract (click to expand)
&lt;/summary&gt;
&lt;cite&gt;&lt;div&gt;
      &lt;p&gt;In the past few years, the approach to application state in React has been constantly shifting. Local component state has been complemented with global state management solutions like ‘react-redux’ or ‘mobx-react’. The introduction of GraphQL libraries like Apollo brought new approaches to API caching (at least for GraphQL). With the release of React 16.3, the reworked Context API has been finally declared stable, adding a viable option for small and simple global states.&lt;/p&gt;

      &lt;p&gt;As a part of the forthcoming React 16.7, hooks will allow for easier use of local state as well as context in function components. Existing libraries are already discussing new hook-compatible APIs that will change the way we are using them. Furthermore, the upcoming ‘suspense’ mechanism is bound to spawn the birth of at least a few new libraries with focus on “perceived local” data fetching and caching.&lt;/p&gt;

      &lt;p&gt;Unfortunately, there is no “one size fits all” solution when evaluating these approaches. This talk will highlight the different types of state occurring in modern React applications and give recommendations on how to approach them with the tools currently available, with an outlook on the near future.&lt;/p&gt;
    &lt;/div&gt;&lt;/cite&gt;
&lt;/details&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://phryneas.github.io/talk-ijs_london-state_of_react_state_2019/&quot;&gt;Slides&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/phryneas/talk-ijs_london-state_of_react_state_2019&quot;&gt;Code examples&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=dPY8y4CB3mI&quot;&gt;Video&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Tue, 14 May 2019 00:00:00 +0000</pubDate>
        <link>https://www.phryneas.de/ijs-london-2019-talk</link>
        <guid isPermaLink="true">https://www.phryneas.de/ijs-london-2019-talk</guid>
        
        
      </item>
    
  </channel>
</rss>
