{"id":1406,"date":"2023-11-17T07:55:00","date_gmt":"2023-11-17T07:55:00","guid":{"rendered":"https:\/\/codereviewvideos.com\/?p=1406"},"modified":"2023-11-11T11:20:16","modified_gmt":"2023-11-11T11:20:16","slug":"react-usereducer-typescript-example","status":"publish","type":"post","link":"https:\/\/codereviewvideos.com\/react-usereducer-typescript-example\/","title":{"rendered":"React useReducer TypeScript Example"},"content":{"rendered":"\n<p>Of all the hooks available in React, <code>useReducer<\/code> is easily my favourite. It&#8217;s nice to be able to solve simple problems with <code>useState<\/code>, but in component&#8217;s with even a smaller amount of complexity than can be solved with a boolean state value, I tend to favour <code>useReducer<\/code>. <\/p>\n\n\n\n<p>Let&#8217;s dig in, see some examples, and find out why.<\/p>\n\n\n\n<p>The examples I&#8217;m going to use are somewhat trivial only for the purposes of easy demonstration. The concepts learned are useful on larger, more complex components. <\/p>\n\n\n\n\n\n<h2 class=\"wp-block-heading\">From useState to useReducer<\/h2>\n\n\n\n<p>The first example is a simple JavaScript \/ JSX counter component. For me, this would actually be preferable to keep as using the <code>useState<\/code> approach, but showing a way we are all familiar with, and how that transfers to <code>useReducer<\/code> has some value, I feel. <\/p>\n\n\n\n<p>OK, here we go:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-comment\">\/\/ src\/Counter.jsx<\/span>\n\n<span class=\"hljs-keyword\">import<\/span> React, { useState } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'react'<\/span>;\n\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">Counter<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> &#091;count, setCount] = useState(<span class=\"hljs-number\">0<\/span>);\n\n  <span class=\"hljs-keyword\">const<\/span> increment = <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n    setCount(count + <span class=\"hljs-number\">1<\/span>);\n  };\n\n  <span class=\"hljs-keyword\">const<\/span> decrement = <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n    setCount(count - <span class=\"hljs-number\">1<\/span>);\n  };\n\n  <span class=\"hljs-keyword\">return<\/span> (\n    <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span>&gt;<\/span>Count: {count}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span> <span class=\"hljs-attr\">onClick<\/span>=<span class=\"hljs-string\">{increment}<\/span>&gt;<\/span>Increment<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span> <span class=\"hljs-attr\">onClick<\/span>=<span class=\"hljs-string\">{decrement}<\/span>&gt;<\/span>Decrement<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span>\n  );\n}\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> Counter;<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p> You could &#8216;upgrade&#8217; this to a TypeScript component very easily:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"TypeScript\" data-shcb-language-slug=\"typescript\"><span><code class=\"hljs language-typescript shcb-code-table\"><mark class='shcb-loc'><span><span class=\"hljs-comment\">\/\/ src\/Counter.tsx<\/span>\n<\/span><\/mark><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">import<\/span> React, { useState } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'react'<\/span>;\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">Counter<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n<\/span><\/span><mark class='shcb-loc'><span>  <span class=\"hljs-keyword\">const<\/span> &#091;count, setCount] = useState&lt;<span class=\"hljs-built_in\">number<\/span>&gt;(<span class=\"hljs-number\">0<\/span>);\n<\/span><\/mark><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">const<\/span> increment = <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n<\/span><\/span><span class='shcb-loc'><span>    setCount(count + <span class=\"hljs-number\">1<\/span>);\n<\/span><\/span><span class='shcb-loc'><span>  };\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">const<\/span> decrement = <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n<\/span><\/span><span class='shcb-loc'><span>    setCount(count - <span class=\"hljs-number\">1<\/span>);\n<\/span><\/span><span class='shcb-loc'><span>  };\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">return<\/span> (\n<\/span><\/span><span class='shcb-loc'><span>    &lt;div&gt;\n<\/span><\/span><span class='shcb-loc'><span>      &lt;p&gt;Count: {count}&lt;<span class=\"hljs-regexp\">\/p&gt;<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-regexp\">      &lt;button onClick={increment}&gt;Increment&lt;\/<\/span>button&gt;\n<\/span><\/span><span class='shcb-loc'><span>      &lt;button onClick={decrement}&gt;Decrement&lt;<span class=\"hljs-regexp\">\/button&gt;<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-regexp\">    &lt;\/<\/span>div&gt;\n<\/span><\/span><span class='shcb-loc'><span>  );\n<\/span><\/span><span class='shcb-loc'><span>}\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> Counter;\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">TypeScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">typescript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>In this TypeScript version, we explicitly specify the type of the <code>count<\/code> state using <code>useState&lt;number&gt;(0)<\/code>. This tells TypeScript that <code>count<\/code> is expected to be a number.<\/p>\n\n\n\n<p>It really doesn&#8217;t make a huge amount of difference at this stage. But the types will come to help us as we progress.<\/p>\n\n\n\n<p>In our current Counter component implementation we start with a number, <code>0<\/code> by default. <\/p>\n\n\n\n<p>We can then click on a button to add one to the number, or remove one from the number.<\/p>\n\n\n\n<p>I&#8217;ve added a bit of style using Tailwinds and Daisy UI, and without much effort we have something looking like this:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"287\" height=\"124\" data-attachment-id=\"1407\" data-permalink=\"https:\/\/codereviewvideos.com\/react-usereducer-typescript-example\/simple-counter-component-react-use-state\/#main\" data-orig-file=\"https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/11\/simple-counter-component-react-use-state.png?fit=287%2C124&amp;ssl=1\" data-orig-size=\"287,124\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"simple-counter-component-react-use-state\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/11\/simple-counter-component-react-use-state.png?fit=287%2C124&amp;ssl=1\" src=\"https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/11\/simple-counter-component-react-use-state.png?resize=287%2C124&#038;ssl=1\" alt=\"\" class=\"wp-image-1407\"\/><\/figure>\n<\/div>\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">    &lt;div&gt;\n      <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"text-3xl mb-4\"<\/span>&gt;<\/span>Count: {count}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span><\/span>\n      <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span> <span class=\"hljs-attr\">onClick<\/span>=<span class=\"hljs-string\">{increment}<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"btn btn-neutral mr-2\"<\/span>&gt;<\/span>\n        Increment\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span><\/span>\n      <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span> <span class=\"hljs-attr\">onClick<\/span>=<span class=\"hljs-string\">{decrement}<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"btn btn-neutral\"<\/span>&gt;<\/span>\n        Decrement\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span><\/span>\n    &lt;<span class=\"hljs-regexp\">\/div&gt;<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Let&#8217;s pretend our Counter website suddenly got to the front page of Reddit, and usage is going to the moon \ud83d\ude80\ud83c\udf1a<\/p>\n\n\n\n<p>Feature requests are flying in left and right. The biggest request, by far, is for a way to reset the counter.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Adding A &#8216;Reset&#8217; Functionality<\/h3>\n\n\n\n<p>In this example, we&#8217;re managing the state of the count using <code>useState<\/code>. Now, let&#8217;s add a feature to reset the count back to the initial value. With <code>useState<\/code>, you can do it like this:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-comment\">\/\/ src\/Counter.jsx<\/span>\n\n<span class=\"hljs-keyword\">import<\/span> React, { useState } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'react'<\/span>;\n\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">Counter<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> &#091;count, setCount] = useState(<span class=\"hljs-number\">0<\/span>);\n\n  <span class=\"hljs-keyword\">const<\/span> increment = <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n    setCount(count + <span class=\"hljs-number\">1<\/span>);\n  };\n\n  <span class=\"hljs-keyword\">const<\/span> decrement = <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n    setCount(count - <span class=\"hljs-number\">1<\/span>);\n  };\n\n  <span class=\"hljs-keyword\">const<\/span> reset = <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n    setCount(<span class=\"hljs-number\">0<\/span>);\n  };\n\n  <span class=\"hljs-keyword\">return<\/span> (\n    <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span>&gt;<\/span>Count: {count}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span> <span class=\"hljs-attr\">onClick<\/span>=<span class=\"hljs-string\">{increment}<\/span>&gt;<\/span>Increment<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span> <span class=\"hljs-attr\">onClick<\/span>=<span class=\"hljs-string\">{decrement}<\/span>&gt;<\/span>Decrement<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span> <span class=\"hljs-attr\">onClick<\/span>=<span class=\"hljs-string\">{reset}<\/span>&gt;<\/span>Reset<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span>\n  );\n}\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> Counter;<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>With three different actions I&#8217;d already be starting to consider <code>useReducer<\/code>. These are simple transitions, but in reality our components often are more complex, even with a small handful of possible states. The more complex the state, the more complex the transitions between states, and once you have a bunch of components in play, remembering how everything works down to the nitty gritty can become challenging.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"369\" height=\"150\" data-attachment-id=\"1413\" data-permalink=\"https:\/\/codereviewvideos.com\/react-usereducer-typescript-example\/counter-component-with-reset\/#main\" data-orig-file=\"https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/11\/counter-component-with-reset.png?fit=369%2C150&amp;ssl=1\" data-orig-size=\"369,150\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"counter-component-with-reset\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/11\/counter-component-with-reset.png?fit=369%2C150&amp;ssl=1\" src=\"https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/11\/counter-component-with-reset.png?resize=369%2C150&#038;ssl=1\" alt=\"react counter component with reset button\" class=\"wp-image-1413\" srcset=\"https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/11\/counter-component-with-reset.png?w=369&amp;ssl=1 369w, https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/11\/counter-component-with-reset.png?resize=300%2C122&amp;ssl=1 300w\" sizes=\"auto, (max-width: 369px) 100vw, 369px\" \/><\/figure>\n<\/div>\n\n\n<p>Let&#8217;s see how this same component might look when using <code>useReducer<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-comment\">\/\/ src\/Counter.jsx<\/span>\n\n<span class=\"hljs-keyword\">import<\/span> React, { useReducer } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'react'<\/span>;\n\n<span class=\"hljs-keyword\">const<\/span> initialState = { <span class=\"hljs-attr\">count<\/span>: <span class=\"hljs-number\">0<\/span> };\n\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">reducer<\/span>(<span class=\"hljs-params\">state, action<\/span>) <\/span>{\n  <span class=\"hljs-keyword\">switch<\/span> (action.type) {\n    <span class=\"hljs-keyword\">case<\/span> <span class=\"hljs-string\">'INCREMENT'<\/span>:\n      <span class=\"hljs-keyword\">return<\/span> { <span class=\"hljs-attr\">count<\/span>: state.count + <span class=\"hljs-number\">1<\/span> };\n    <span class=\"hljs-keyword\">case<\/span> <span class=\"hljs-string\">'DECREMENT'<\/span>:\n      <span class=\"hljs-keyword\">return<\/span> { <span class=\"hljs-attr\">count<\/span>: state.count - <span class=\"hljs-number\">1<\/span> };\n    <span class=\"hljs-keyword\">case<\/span> <span class=\"hljs-string\">'RESET'<\/span>:\n      <span class=\"hljs-keyword\">return<\/span> initialState;\n    <span class=\"hljs-keyword\">default<\/span>:\n      <span class=\"hljs-keyword\">return<\/span> state;\n  }\n}\n\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">Counter<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> &#091;state, dispatch] = useReducer(reducer, initialState);\n\n  <span class=\"hljs-keyword\">return<\/span> (\n    <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span>&gt;<\/span>Count: {state.count}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span> <span class=\"hljs-attr\">onClick<\/span>=<span class=\"hljs-string\">{()<\/span> =&gt;<\/span> dispatch({ type: 'INCREMENT' })}&gt;Increment<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span> <span class=\"hljs-attr\">onClick<\/span>=<span class=\"hljs-string\">{()<\/span> =&gt;<\/span> dispatch({ type: 'DECREMENT' })}&gt;Decrement<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span> <span class=\"hljs-attr\">onClick<\/span>=<span class=\"hljs-string\">{()<\/span> =&gt;<\/span> dispatch({ type: 'RESET' })}&gt;Reset<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span>\n  );\n}\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> Counter;<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>I was going to do a line highlight here of everything that changed, but, well&#8230; everything has changed \ud83d\ude42<\/p>\n\n\n\n<p>Well, I say that, but only the internals have changed. The behaviour is actually fundamentally identical to what we had in the <code>useState<\/code> example. <\/p>\n\n\n\n<p>Let&#8217;s break down the component and its key elements:<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Initial State<\/h4>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">   <span class=\"hljs-keyword\">const<\/span> initialState = { <span class=\"hljs-attr\">count<\/span>: <span class=\"hljs-number\">0<\/span> };<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Here, <code>initialState<\/code> defines the initial state of the component, which includes a single property <code>count<\/code> initialised to <code>0<\/code>.  <\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Reducer Function<\/h4>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">   <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">reducer<\/span>(<span class=\"hljs-params\">state, action<\/span>) <\/span>{\n     <span class=\"hljs-keyword\">switch<\/span> (action.type) {\n       <span class=\"hljs-keyword\">case<\/span> <span class=\"hljs-string\">'INCREMENT'<\/span>:\n         <span class=\"hljs-keyword\">return<\/span> { <span class=\"hljs-attr\">count<\/span>: state.count + <span class=\"hljs-number\">1<\/span> };\n       <span class=\"hljs-keyword\">case<\/span> <span class=\"hljs-string\">'DECREMENT'<\/span>:\n         <span class=\"hljs-keyword\">return<\/span> { <span class=\"hljs-attr\">count<\/span>: state.count - <span class=\"hljs-number\">1<\/span> };\n       <span class=\"hljs-keyword\">case<\/span> <span class=\"hljs-string\">'RESET'<\/span>:\n         <span class=\"hljs-keyword\">return<\/span> initialState;\n       <span class=\"hljs-keyword\">default<\/span>:\n         <span class=\"hljs-keyword\">return<\/span> state;\n     }\n   }<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>The <code>reducer<\/code> function is responsible for updating the state based on different actions that we define. <\/p>\n\n\n\n<p>The <code>reducer<\/code> function takes the current state and an action object as parameters and returns a new state.<\/p>\n\n\n\n<p>In this case, it handles three types of actions: <code>'INCREMENT'<\/code>, <code>'DECREMENT'<\/code>, and <code>'RESET'<\/code>. <\/p>\n\n\n\n<p>Depending on the action type, it updates the <code>count<\/code> property of the state accordingly.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><code>useReducer<\/code> Hook<\/h4>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">   <span class=\"hljs-keyword\">const<\/span> &#091;state, dispatch] = useReducer(reducer, initialState);<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>The <code>useReducer<\/code> hook is used to manage state in a more structured way. It takes two arguments: the <code>reducer<\/code> function and the <code>initialState<\/code>. <\/p>\n\n\n\n<p>Much like <code>useState<\/code>, it returns an array with two elements:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>state<\/code>: This holds the current state, which is initially set to <code>initialState<\/code>.<\/li>\n\n\n\n<li><code>dispatch<\/code>: This is a function used to dispatch actions to the reducer, triggering state updates.<\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\">Rendered UI<\/h4>\n\n\n\n<p>Finally we have the actual output of our component. For simplicity I&#8217;ve kept the styles off this output. <\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\">   <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n     <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span>&gt;<\/span>Count: {state.count}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n     <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span> <span class=\"hljs-attr\">onClick<\/span>=<span class=\"hljs-string\">{()<\/span> =&gt;<\/span> dispatch({ type: 'INCREMENT' })}&gt;Increment<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span>\n     <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span> <span class=\"hljs-attr\">onClick<\/span>=<span class=\"hljs-string\">{()<\/span> =&gt;<\/span> dispatch({ type: 'DECREMENT' })}&gt;Decrement<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span>\n     <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span> <span class=\"hljs-attr\">onClick<\/span>=<span class=\"hljs-string\">{()<\/span> =&gt;<\/span> dispatch({ type: 'RESET' })}&gt;Reset<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span>\n   <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>We start by displaying the current value of <code>count<\/code> from the <code>state<\/code> object. <\/p>\n\n\n\n<p>Then there are the three buttons: &#8220;Increment,&#8221; &#8220;Decrement,&#8221; and &#8220;Reset.&#8221; <\/p>\n\n\n\n<p>When these buttons are clicked, they dispatch the corresponding action to the <code>reducer<\/code> function by calling <code>dispatch({ type: 'OUR_ACTION_TYPE' })<\/code>.<\/p>\n\n\n\n<p>WebStorm actually gets a bit unhappy about some of this:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"753\" height=\"1024\" data-attachment-id=\"1408\" data-permalink=\"https:\/\/codereviewvideos.com\/react-usereducer-typescript-example\/simple-counter-component-react-use-reducer\/#main\" data-orig-file=\"https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/11\/simple-counter-component-react-use-reducer.png?fit=843%2C1147&amp;ssl=1\" data-orig-size=\"843,1147\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"simple-counter-component-react-use-reducer\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/11\/simple-counter-component-react-use-reducer.png?fit=753%2C1024&amp;ssl=1\" src=\"https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/11\/simple-counter-component-react-use-reducer.png?resize=753%2C1024&#038;ssl=1\" alt=\"usereducer counter example webstorm\" class=\"wp-image-1408\" srcset=\"https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/11\/simple-counter-component-react-use-reducer.png?resize=753%2C1024&amp;ssl=1 753w, https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/11\/simple-counter-component-react-use-reducer.png?resize=220%2C300&amp;ssl=1 220w, https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/11\/simple-counter-component-react-use-reducer.png?resize=768%2C1045&amp;ssl=1 768w, https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/11\/simple-counter-component-react-use-reducer.png?w=843&amp;ssl=1 843w\" sizes=\"auto, (max-width: 753px) 100vw, 753px\" \/><\/figure>\n\n\n\n<p>You can see a few bits are lightly underlined. No errors here, just warnings. <\/p>\n\n\n\n<p>They all go away if we convert over to TypeScript:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"TypeScript\" data-shcb-language-slug=\"typescript\"><span><code class=\"hljs language-typescript shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span><span class=\"hljs-comment\">\/\/ src\/Counter.tsx<\/span>\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">import<\/span> React, { useReducer } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"react\"<\/span>;\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><mark class='shcb-loc'><span><span class=\"hljs-keyword\">interface<\/span> State {\n<\/span><\/mark><mark class='shcb-loc'><span>  count: <span class=\"hljs-built_in\">number<\/span>;\n<\/span><\/mark><mark class='shcb-loc'><span>}\n<\/span><\/mark><span class='shcb-loc'><span>\n<\/span><\/span><mark class='shcb-loc'><span><span class=\"hljs-keyword\">type<\/span> Action = { <span class=\"hljs-keyword\">type<\/span>: <span class=\"hljs-string\">\"INCREMENT\"<\/span> } | { <span class=\"hljs-keyword\">type<\/span>: <span class=\"hljs-string\">\"DECREMENT\"<\/span> } | { <span class=\"hljs-keyword\">type<\/span>: <span class=\"hljs-string\">\"RESET\"<\/span> };\n<\/span><\/mark><span class='shcb-loc'><span>\n<\/span><\/span><mark class='shcb-loc'><span><span class=\"hljs-keyword\">const<\/span> initialState: State = { count: <span class=\"hljs-number\">0<\/span> };\n<\/span><\/mark><span class='shcb-loc'><span>\n<\/span><\/span><mark class='shcb-loc'><span><span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">reducer<\/span>(<span class=\"hljs-params\">state: State, action: Action<\/span>): <span class=\"hljs-title\">State<\/span> <\/span>{\n<\/span><\/mark><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">switch<\/span> (action.type) {\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-keyword\">case<\/span> <span class=\"hljs-string\">\"INCREMENT\"<\/span>:\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-keyword\">return<\/span> { count: state.count + <span class=\"hljs-number\">1<\/span> };\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-keyword\">case<\/span> <span class=\"hljs-string\">\"DECREMENT\"<\/span>:\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-keyword\">return<\/span> { count: state.count - <span class=\"hljs-number\">1<\/span> };\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-keyword\">case<\/span> <span class=\"hljs-string\">\"RESET\"<\/span>:\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-keyword\">return<\/span> initialState;\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-keyword\">default<\/span>:\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-keyword\">return<\/span> state;\n<\/span><\/span><span class='shcb-loc'><span>  }\n<\/span><\/span><span class='shcb-loc'><span>}\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">Counter<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">const<\/span> &#091;state, dispatch] = useReducer(reducer, initialState);\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">return<\/span> (\n<\/span><\/span><span class='shcb-loc'><span>    &lt;div&gt;\n<\/span><\/span><span class='shcb-loc'><span>      &lt;p&gt;Count: {state.count}&lt;<span class=\"hljs-regexp\">\/p&gt;<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-regexp\">      &lt;button onClick={() =&gt; dispatch({ type: \"INCREMENT\" })}&gt;Increment&lt;\/<\/span>button&gt;\n<\/span><\/span><span class='shcb-loc'><span>      &lt;button onClick={<span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> dispatch({ <span class=\"hljs-keyword\">type<\/span>: <span class=\"hljs-string\">\"DECREMENT\"<\/span> })}&gt;Decrement&lt;<span class=\"hljs-regexp\">\/button&gt;<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-function\"><span class=\"hljs-regexp\">      &lt;button onClick={() =&gt; dispatch({ type: \"RESET\" })}&gt;Reset&lt;\/<\/span>button&gt;<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-function\">    &lt;<span class=\"hljs-regexp\">\/div&gt;<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-function\"><span class=\"hljs-regexp\">  );<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-function\"><span class=\"hljs-regexp\">}<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-function\"><span class=\"hljs-regexp\"><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-function\"><span class=\"hljs-regexp\">export default Counter;<\/span><\/span>\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">TypeScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">typescript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>In the TypeScript version we need to tell TypeScript exactly what kind of things we expect and allow. <\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Initial State<\/h4>\n\n\n\n<p>On lines 5-7 we define a custom <code>interface<\/code>. It could be called anything, but as it will represent the components internal state, I went with the name <code>State<\/code>. <\/p>\n\n\n\n<p>Our component handles one piece of state, and that is the <code>count<\/code>. The <code>count<\/code> is a <code>number<\/code>, much like we had back when we typed <code>useState<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-11\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\">const &#091;count, setCount] = useState<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">number<\/span>&gt;<\/span>(0);<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-11\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h4 class=\"wp-block-heading\">Action Type<\/h4>\n\n\n\n<p>The <code>Action<\/code> type is really where the most interesting part of this change occurs. <\/p>\n\n\n\n<p>Again, <code>Action<\/code> is just a name. But it explains what concept we are wanting to describe. <\/p>\n\n\n\n<p>Our component has three different things it can do. Three actions. Again, you don&#8217;t need to follow the convention given, but it&#8217;s really common to use a <code>type<\/code> key, and then a string property, typically in uppercase, to describe what is happening. <\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-12\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">type Action = { <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-string\">\"INCREMENT\"<\/span> } | { <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-string\">\"DECREMENT\"<\/span> } | { <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-string\">\"RESET\"<\/span> };<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-12\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Here we have a union type &#8211; denoted by the pipe between the three different type definitions. <\/p>\n\n\n\n<p>You could also write this as:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-13\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">type Action = \n  | { <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-string\">\"INCREMENT\"<\/span> } \n  | { <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-string\">\"DECREMENT\"<\/span> } \n  | { <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-string\">\"RESET\"<\/span> };<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-13\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Which says that when we type something to be <code>Action<\/code>, it may be an object in any of them three different shapes.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-14\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">const<\/span> initialState: State = { <span class=\"hljs-attr\">count<\/span>: <span class=\"hljs-number\">0<\/span> };<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-14\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>We defined the <code>State<\/code> interface, and now we tell TypeScript that our <code>initialState<\/code> object should have that type. In other words, <code>initialState<\/code> should be an object that has a <code>count<\/code> property with a numerical value. <\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Typed Reducer<\/h4>\n\n\n\n<p>And then we can add types to our <code>reducer<\/code> function:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-15\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">reducer<\/span>(<span class=\"hljs-params\">state: State, action: Action<\/span>): <span class=\"hljs-title\">State<\/span> <\/span>{<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-15\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Which brings this all together.<\/p>\n\n\n\n<p>The <code>reducer<\/code> function takes our two arguments, just like we covered earlier, only now they are typed.<\/p>\n\n\n\n<p>The first argument is going to an object that has the type \/ shape of the <code>State<\/code> interface. So, again, some object that has a <code>count<\/code> property with a numerical value. It could be anything. Whatever properties you defined on your own component&#8217;s <code>State<\/code>. <\/p>\n\n\n\n<p>And then an <code>action<\/code>.<\/p>\n\n\n\n<p>That action can <strong>only<\/strong> be one of the three actions, in exactly those shapes, that we defined in the <code>Action<\/code> type. This works super well to give us some lovely intelli-sense \/ autocomplete in our IDE.<\/p>\n\n\n\n<p>You can see this in action. When you use the <code>dispatch<\/code> function in your code, TypeScript is now clever enough to work out that the only viable and allowable arguments must match one of the <code>Action<\/code> shapes you defined:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"247\" data-attachment-id=\"1410\" data-permalink=\"https:\/\/codereviewvideos.com\/react-usereducer-typescript-example\/typescript-usereducer-action-typing\/#main\" data-orig-file=\"https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/11\/typescript-usereducer-action-typing.png?fit=1129%2C272&amp;ssl=1\" data-orig-size=\"1129,272\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"typescript-usereducer-action-typing\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/11\/typescript-usereducer-action-typing.png?fit=1024%2C247&amp;ssl=1\" src=\"https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/11\/typescript-usereducer-action-typing.png?resize=1024%2C247&#038;ssl=1\" alt=\"typescript react component usereducer action typing\" class=\"wp-image-1410\" srcset=\"https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/11\/typescript-usereducer-action-typing.png?resize=1024%2C247&amp;ssl=1 1024w, https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/11\/typescript-usereducer-action-typing.png?resize=300%2C72&amp;ssl=1 300w, https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/11\/typescript-usereducer-action-typing.png?resize=768%2C185&amp;ssl=1 768w, https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/11\/typescript-usereducer-action-typing.png?w=1129&amp;ssl=1 1129w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>If you try to use a <code>type<\/code> that you didn&#8217;t specify in your <code>Action<\/code> type, or you add in some extra or incorrect property, TypeScript will throw out various warnings, and may stop you from compiling your code &#8211; depending on how strict your settings are in <code>tsconfig.json<\/code>. <\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-16\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css shcb-wrap-lines\"><span class=\"hljs-selector-tag\">TS2345<\/span>: <span class=\"hljs-selector-tag\">Argument<\/span> <span class=\"hljs-selector-tag\">of<\/span> <span class=\"hljs-selector-tag\">type<\/span> { <span class=\"hljs-attribute\">type<\/span>: <span class=\"hljs-string\">\"INCREMENT\"<\/span>; <span class=\"hljs-attribute\">someExtraKey<\/span>: string; } <span class=\"hljs-selector-tag\">is<\/span> <span class=\"hljs-selector-tag\">not<\/span> <span class=\"hljs-selector-tag\">assignable<\/span> <span class=\"hljs-selector-tag\">to<\/span> <span class=\"hljs-selector-tag\">parameter<\/span> <span class=\"hljs-selector-tag\">of<\/span> <span class=\"hljs-selector-tag\">type<\/span> <span class=\"hljs-selector-tag\">Action<\/span>\n<span class=\"hljs-selector-tag\">Object<\/span> <span class=\"hljs-selector-tag\">literal<\/span> <span class=\"hljs-selector-tag\">may<\/span> <span class=\"hljs-selector-tag\">only<\/span> <span class=\"hljs-selector-tag\">specify<\/span> <span class=\"hljs-selector-tag\">known<\/span> <span class=\"hljs-selector-tag\">properties<\/span>, <span class=\"hljs-selector-tag\">and<\/span> <span class=\"hljs-selector-tag\">someExtraKey<\/span> <span class=\"hljs-selector-tag\">does<\/span> <span class=\"hljs-selector-tag\">not<\/span> <span class=\"hljs-selector-tag\">exist<\/span> <span class=\"hljs-selector-tag\">in<\/span> <span class=\"hljs-selector-tag\">type<\/span> { <span class=\"hljs-attribute\">type<\/span>: <span class=\"hljs-string\">\"INCREMENT\"<\/span>; }<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-16\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>That might seem trivial on a small example component like this, but on larger projects, and with components you personally didn&#8217;t create, it can be a super helpful thing in my experience. <\/p>\n\n\n\n<p>With this, WebStorm is really quite happy:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"631\" height=\"1024\" data-attachment-id=\"1409\" data-permalink=\"https:\/\/codereviewvideos.com\/react-usereducer-typescript-example\/webstorm-use-reducer-typescript-example\/#main\" data-orig-file=\"https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/11\/webstorm-use-reducer-typescript-example.png?fit=810%2C1314&amp;ssl=1\" data-orig-size=\"810,1314\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"webstorm-use-reducer-typescript-example\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/11\/webstorm-use-reducer-typescript-example.png?fit=631%2C1024&amp;ssl=1\" src=\"https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/11\/webstorm-use-reducer-typescript-example-631x1024.png?resize=631%2C1024&#038;ssl=1\" alt=\"webstorm react component usereducer typescript example\" class=\"wp-image-1409\" srcset=\"https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/11\/webstorm-use-reducer-typescript-example.png?resize=631%2C1024&amp;ssl=1 631w, https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/11\/webstorm-use-reducer-typescript-example.png?resize=185%2C300&amp;ssl=1 185w, https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/11\/webstorm-use-reducer-typescript-example.png?resize=768%2C1246&amp;ssl=1 768w, https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/11\/webstorm-use-reducer-typescript-example.png?w=810&amp;ssl=1 810w\" sizes=\"auto, (max-width: 631px) 100vw, 631px\" \/><\/figure>\n\n\n\n<p>Let&#8217;s look at one more example, which is a little more complex.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Shopping Basket Example<\/h2>\n\n\n\n<p>Whilst the Counter component shows everything involved in <code>useReducer<\/code> for pretty much every use case I&#8217;ve ever had, it still might not sell the idea to you because the example is trivial.<\/p>\n\n\n\n<p>If we look at a slightly more complex component, the use of a <code>reducer<\/code> function &#8211; and how testable that function is &#8211; should hopefully sell this concept to you, if you aren&#8217;t already sold. <\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Using useState for Shopping Basket<\/h3>\n\n\n\n<p>We&#8217;ll start with <code>useState<\/code> and then refactor it to use <code>useReducer<\/code> to illustrate how and why <code>useReducer<\/code> can be a better approach in more complex scenarios:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-17\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-comment\">\/\/ src\/ShoppingBasket.jsx<\/span>\n\n<span class=\"hljs-keyword\">import<\/span> React, { useState } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"react\"<\/span>;\n\n<span class=\"hljs-keyword\">const<\/span> productVariations = &#091;\n  { <span class=\"hljs-attr\">id<\/span>: <span class=\"hljs-number\">1<\/span>, <span class=\"hljs-attr\">name<\/span>: <span class=\"hljs-string\">\"Product 1\"<\/span>, <span class=\"hljs-attr\">price<\/span>: <span class=\"hljs-number\">10<\/span> },\n  { <span class=\"hljs-attr\">id<\/span>: <span class=\"hljs-number\">2<\/span>, <span class=\"hljs-attr\">name<\/span>: <span class=\"hljs-string\">\"Product 2\"<\/span>, <span class=\"hljs-attr\">price<\/span>: <span class=\"hljs-number\">5<\/span> },\n  { <span class=\"hljs-attr\">id<\/span>: <span class=\"hljs-number\">3<\/span>, <span class=\"hljs-attr\">name<\/span>: <span class=\"hljs-string\">\"Product 3\"<\/span>, <span class=\"hljs-attr\">price<\/span>: <span class=\"hljs-number\">15<\/span> },\n  { <span class=\"hljs-attr\">id<\/span>: <span class=\"hljs-number\">4<\/span>, <span class=\"hljs-attr\">name<\/span>: <span class=\"hljs-string\">\"Product 4\"<\/span>, <span class=\"hljs-attr\">price<\/span>: <span class=\"hljs-number\">8<\/span> },\n  { <span class=\"hljs-attr\">id<\/span>: <span class=\"hljs-number\">5<\/span>, <span class=\"hljs-attr\">name<\/span>: <span class=\"hljs-string\">\"Product 5\"<\/span>, <span class=\"hljs-attr\">price<\/span>: <span class=\"hljs-number\">12<\/span> },\n];\n\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">ShoppingBasket<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> &#091;basket, setBasket] = useState(&#091;]);\n  <span class=\"hljs-keyword\">const<\/span> &#091;total, setTotal] = useState(<span class=\"hljs-number\">0<\/span>);\n\n  <span class=\"hljs-keyword\">const<\/span> addToBasket = <span class=\"hljs-function\">(<span class=\"hljs-params\">product<\/span>) =&gt;<\/span> {\n    setBasket(&#091;...basket, product]);\n    setTotal(total + product.price);\n  };\n\n  <span class=\"hljs-keyword\">const<\/span> isProductInBasket = <span class=\"hljs-function\">(<span class=\"hljs-params\">productId<\/span>) =&gt;<\/span> {\n    <span class=\"hljs-keyword\">return<\/span> basket.some(<span class=\"hljs-function\">(<span class=\"hljs-params\">product<\/span>) =&gt;<\/span> product.id === productId);\n  };\n\n  <span class=\"hljs-keyword\">const<\/span> removeFromBasket = <span class=\"hljs-function\">(<span class=\"hljs-params\">product<\/span>) =&gt;<\/span> {\n    <span class=\"hljs-keyword\">const<\/span> updatedBasket = basket.filter(<span class=\"hljs-function\">(<span class=\"hljs-params\">item<\/span>) =&gt;<\/span> item.id !== product.id);\n    setBasket(updatedBasket);\n    setTotal(total - product.price);\n  };\n\n  <span class=\"hljs-keyword\">const<\/span> resetBasket = <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n    setBasket(&#091;]);\n    setTotal(<span class=\"hljs-number\">0<\/span>);\n  };\n\n  <span class=\"hljs-keyword\">return<\/span> (\n    <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h2<\/span>&gt;<\/span>Shopping Basket<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h2<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">ul<\/span>&gt;<\/span>\n        {basket.map((product) =&gt; (\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">li<\/span> <span class=\"hljs-attr\">key<\/span>=<span class=\"hljs-string\">{product.id}<\/span>&gt;<\/span>\n            {product.name} - \u00a3{product.price}\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span>\n              <span class=\"hljs-attr\">onClick<\/span>=<span class=\"hljs-string\">{()<\/span> =&gt;<\/span> removeFromBasket(product)}\n            &gt;\n              Remove\n            <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">li<\/span>&gt;<\/span>\n        ))}\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">ul<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span>&gt;<\/span>Total: \u00a3{total}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n        {productVariations.map((product) =&gt; (\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span>\n            <span class=\"hljs-attr\">key<\/span>=<span class=\"hljs-string\">{product.id}<\/span>\n            <span class=\"hljs-attr\">onClick<\/span>=<span class=\"hljs-string\">{()<\/span> =&gt;<\/span> addToBasket(product)}\n            disabled={isProductInBasket(product.id)}\n          &gt;\n            Add {product.name}\n          <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span>\n        ))}\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span> <span class=\"hljs-attr\">onClick<\/span>=<span class=\"hljs-string\">{resetBasket}<\/span>&gt;<\/span>\n          Reset Basket\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span>\n    &lt;<span class=\"hljs-regexp\">\/div&gt;\n  );\n}\n\nexport default ShoppingBasket;<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-17\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Here&#8217;s how that looks with a bit of style applied:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"574\" height=\"230\" data-attachment-id=\"1433\" data-permalink=\"https:\/\/codereviewvideos.com\/react-usereducer-typescript-example\/use-reducer-shopping-basket-example-1\/#main\" data-orig-file=\"https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/11\/use-reducer-shopping-basket-example-1.png?fit=574%2C230&amp;ssl=1\" data-orig-size=\"574,230\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"use-reducer-shopping-basket-example-1\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/11\/use-reducer-shopping-basket-example-1.png?fit=574%2C230&amp;ssl=1\" src=\"https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/11\/use-reducer-shopping-basket-example-1.png?resize=574%2C230&#038;ssl=1\" alt=\"react shopping basket component example\" class=\"wp-image-1433\" srcset=\"https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/11\/use-reducer-shopping-basket-example-1.png?w=574&amp;ssl=1 574w, https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/11\/use-reducer-shopping-basket-example-1.png?resize=300%2C120&amp;ssl=1 300w\" sizes=\"auto, (max-width: 574px) 100vw, 574px\" \/><\/figure>\n<\/div>\n\n\n<p>And the behaviour is you can select each product, in any order, exactly once, before it is disabled \/ unavailable for selection. You can either remove it using the inline button, or clear \/ reset the entire basket:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"565\" height=\"362\" data-attachment-id=\"1434\" data-permalink=\"https:\/\/codereviewvideos.com\/react-usereducer-typescript-example\/use-reducer-shopping-basket-example-2\/#main\" data-orig-file=\"https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/11\/use-reducer-shopping-basket-example-2.png?fit=565%2C362&amp;ssl=1\" data-orig-size=\"565,362\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"use-reducer-shopping-basket-example-2\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/11\/use-reducer-shopping-basket-example-2.png?fit=565%2C362&amp;ssl=1\" src=\"https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/11\/use-reducer-shopping-basket-example-2.png?resize=565%2C362&#038;ssl=1\" alt=\"react shopping basket component example with selections\" class=\"wp-image-1434\" srcset=\"https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/11\/use-reducer-shopping-basket-example-2.png?w=565&amp;ssl=1 565w, https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/11\/use-reducer-shopping-basket-example-2.png?resize=300%2C192&amp;ssl=1 300w\" sizes=\"auto, (max-width: 565px) 100vw, 565px\" \/><\/figure>\n<\/div>\n\n\n<p>Again, it is a trivialised component to a point. The aim is to show the more involved state updates. <\/p>\n\n\n\n<p>Let&#8217;s break down each part of the state manipulation logic:<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">State Initialisation<\/h4>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-18\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">   <span class=\"hljs-keyword\">const<\/span> &#091;basket, setBasket] = useState(&#091;]);\n   <span class=\"hljs-keyword\">const<\/span> &#091;total, setTotal] = useState(<span class=\"hljs-number\">0<\/span>);<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-18\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Two state variables, <code>basket<\/code> and <code>total<\/code>, are initialised using the <code>useState<\/code> hook. <\/p>\n\n\n\n<p><code>basket<\/code> represents the array of products in the shopping basket, and <code>total<\/code> represents the running total cost of the items currently in the basket.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Check if Product is in Basket<\/h4>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-19\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">   <span class=\"hljs-keyword\">const<\/span> isProductInBasket = <span class=\"hljs-function\">(<span class=\"hljs-params\">productId<\/span>) =&gt;<\/span> {\n     <span class=\"hljs-keyword\">return<\/span> basket.some(<span class=\"hljs-function\">(<span class=\"hljs-params\">product<\/span>) =&gt;<\/span> product.id === productId);\n   };<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-19\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>The <code>isProductInBasket<\/code> function takes a <code>productId<\/code> as an argument and checks if a product with that ID is already in the <code>basket<\/code> array. It uses the <code>some<\/code> method to determine if at least one item in the basket has a matching ID.<\/p>\n\n\n\n<p>The use of <code>some<\/code> here is a left over from the original example I coded up. I wanted to be able to add multiple copies of the same product to the basket, but that got even more complicated. <\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Add to Basket<\/h4>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-20\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">   <span class=\"hljs-keyword\">const<\/span> addToBasket = <span class=\"hljs-function\">(<span class=\"hljs-params\">product<\/span>) =&gt;<\/span> {\n     <span class=\"hljs-keyword\">if<\/span> (!isProductInBasket(product.id)) {\n       setBasket(&#091;...basket, product]);\n       setTotal(total + product.price);\n     }\n   };<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-20\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>The <code>addToBasket<\/code> function takes a <code>product<\/code> as an argument and checks if the product is not already in the basket using <code>isProductInBasket<\/code>. <\/p>\n\n\n\n<p>If the product is not in the basket, it updates the <code>basket<\/code> state by adding the new product and increases the <code>total<\/code> by the product&#8217;s price.<\/p>\n\n\n\n<p>Two state updates here, and it&#8217;s critical that both are performed as an individual unit of behaviour. Hmm.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Remove from Basket<\/h4>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-21\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">   <span class=\"hljs-keyword\">const<\/span> removeFromBasket = <span class=\"hljs-function\">(<span class=\"hljs-params\">product<\/span>) =&gt;<\/span> {\n     <span class=\"hljs-keyword\">const<\/span> updatedBasket = basket.filter(<span class=\"hljs-function\">(<span class=\"hljs-params\">item<\/span>) =&gt;<\/span> item.id !== product.id);\n     setBasket(updatedBasket);\n     setTotal(total - product.price);\n   };<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-21\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>The <code>removeFromBasket<\/code> function also takes a <code>product<\/code> as an argument. <\/p>\n\n\n\n<p>It creates a new array, <code>updatedBasket<\/code>, by filtering out the product with the matching ID. <\/p>\n\n\n\n<p>The <code>basket<\/code> state is then updated with this new array, and the <code>total<\/code> is decreased by the price of the removed product.<\/p>\n\n\n\n<p>Again we have two state updates happening in one function, both of which are absolutely critical to this component behaving properly. <\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Reset Basket<\/h4>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-22\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">   <span class=\"hljs-keyword\">const<\/span> resetBasket = <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n     setBasket(&#091;]);\n     setTotal(<span class=\"hljs-number\">0<\/span>);\n   };<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-22\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>The <code>resetBasket<\/code> function sets both the <code>basket<\/code> and <code>total<\/code> states to their initial values, effectively clearing the shopping basket.<\/p>\n\n\n\n<p>We must remember to keep these two setters in sync with the default values used in the State Initialisation step. Yikes. What could go wrong?<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Refactoring the useState Approach to TypeScript<\/h3>\n\n\n\n<p>Before we switch to <code>useReducer<\/code>, let&#8217;s take the existing plain JavaScript <code>ShoppingBasket<\/code> component and rewrite it using TypeScript. <\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-23\" data-shcb-language-name=\"TypeScript\" data-shcb-language-slug=\"typescript\"><span><code class=\"hljs language-typescript\"><span class=\"hljs-comment\">\/\/ src\/ShoppingBasket.tsx<\/span>\n\n<span class=\"hljs-keyword\">import<\/span> React, { useState } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"react\"<\/span>;\n\n<span class=\"hljs-keyword\">interface<\/span> Product {\n  id: <span class=\"hljs-built_in\">number<\/span>;\n  name: <span class=\"hljs-built_in\">string<\/span>;\n  price: <span class=\"hljs-built_in\">number<\/span>;\n}\n\n<span class=\"hljs-keyword\">const<\/span> productVariations: Product&#091;] = &#091;\n  { id: <span class=\"hljs-number\">1<\/span>, name: <span class=\"hljs-string\">\"Product 1\"<\/span>, price: <span class=\"hljs-number\">10<\/span> },\n  { id: <span class=\"hljs-number\">2<\/span>, name: <span class=\"hljs-string\">\"Product 2\"<\/span>, price: <span class=\"hljs-number\">5<\/span> },\n  { id: <span class=\"hljs-number\">3<\/span>, name: <span class=\"hljs-string\">\"Product 3\"<\/span>, price: <span class=\"hljs-number\">15<\/span> },\n  { id: <span class=\"hljs-number\">4<\/span>, name: <span class=\"hljs-string\">\"Product 4\"<\/span>, price: <span class=\"hljs-number\">8<\/span> },\n  { id: <span class=\"hljs-number\">5<\/span>, name: <span class=\"hljs-string\">\"Product 5\"<\/span>, price: <span class=\"hljs-number\">12<\/span> },\n];\n\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">ShoppingBasket<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> &#091;basket, setBasket] = useState&lt;Product&#091;]&gt;(&#091;]);\n  <span class=\"hljs-keyword\">const<\/span> &#091;total, setTotal] = useState&lt;<span class=\"hljs-built_in\">number<\/span>&gt;(<span class=\"hljs-number\">0<\/span>);\n\n  <span class=\"hljs-keyword\">const<\/span> isProductInBasket = (productId: Product&#091;<span class=\"hljs-string\">'id'<\/span>]): <span class=\"hljs-function\"><span class=\"hljs-params\">boolean<\/span> =&gt;<\/span> {\n    <span class=\"hljs-keyword\">return<\/span> basket.some(<span class=\"hljs-function\">(<span class=\"hljs-params\"><span class=\"hljs-params\">product<\/span><\/span>) =&gt;<\/span> product.id === productId);\n  };\n\n  <span class=\"hljs-keyword\">const<\/span> addToBasket = (product: Product): <span class=\"hljs-function\"><span class=\"hljs-params\">void<\/span> =&gt;<\/span> {\n    <span class=\"hljs-keyword\">if<\/span> (!isProductInBasket(product.id)) {\n      setBasket(&#091;...basket, product]);\n      setTotal(total + product.price);\n    }\n  };\n\n  <span class=\"hljs-keyword\">const<\/span> removeFromBasket = (product: Product): <span class=\"hljs-function\"><span class=\"hljs-params\">void<\/span> =&gt;<\/span> {\n    <span class=\"hljs-keyword\">const<\/span> updatedBasket = basket.filter(<span class=\"hljs-function\">(<span class=\"hljs-params\"><span class=\"hljs-params\">item<\/span><\/span>) =&gt;<\/span> item.id !== product.id);\n    setBasket(updatedBasket);\n    setTotal(total - product.price);\n  };\n\n  <span class=\"hljs-keyword\">const<\/span> resetBasket = (): <span class=\"hljs-function\"><span class=\"hljs-params\">void<\/span> =&gt;<\/span> {\n    setBasket(&#091;]);\n    setTotal(<span class=\"hljs-number\">0<\/span>);\n  };\n\n  <span class=\"hljs-keyword\">return<\/span> (\n    &lt;div&gt;\n      &lt;h2&gt;Shopping Basket&lt;<span class=\"hljs-regexp\">\/h2&gt;\n      &lt;ul&gt;\n        {basket.map((product) =&gt; (\n          &lt;li key={product.id}&gt;\n            {product.name} - \u00a3{product.price}\n            &lt;button onClick={() =&gt; removeFromBasket(product)}&gt;Remove&lt;\/<\/span>button&gt;\n          &lt;<span class=\"hljs-regexp\">\/li&gt;\n        ))}\n      &lt;\/u<\/span>l&gt;\n      &lt;p&gt;Total: \u00a3{total}&lt;<span class=\"hljs-regexp\">\/p&gt;\n      {productVariations.map((product) =&gt; (\n        &lt;button\n          key={product.id}\n          onClick={() =&gt; addToBasket(product)}\n          disabled={isProductInBasket(product.id)}\n        &gt;\n          Add {product.name}\n        &lt;\/<\/span>button&gt;\n      ))}\n      &lt;button onClick={resetBasket}&gt;Reset Basket&lt;<span class=\"hljs-regexp\">\/button&gt;\n    &lt;\/<\/span>div&gt;\n  );\n}\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> ShoppingBasket;<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-23\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">TypeScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">typescript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>In this TypeScript version:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>I added the <code>Product<\/code> interface to define the structure of a product.<\/li>\n\n\n\n<li>The <code>basket<\/code> state is explicitly typed as an array of <code>Product<\/code>.<\/li>\n\n\n\n<li>The <code>total<\/code> state is explicitly typed as a <code>number<\/code>.<\/li>\n\n\n\n<li>Function parameters and return types are explicitly typed.<\/li>\n\n\n\n<li>The <code>isProductInBasket<\/code>, <code>addToBasket<\/code>, <code>removeFromBasket<\/code>, and <code>resetBasket<\/code> functions have type annotations for better type safety.<\/li>\n<\/ul>\n\n\n\n<p>There are a couple of things that I want to call out in slightly more detail.<\/p>\n\n\n\n<h5 class=\"wp-block-heading\">Slightly Nicer Basket Reset<\/h5>\n\n\n\n<p>The first is that whilst we do have to still explicitly <code>setBasket<\/code> and <code>setTotal<\/code> back to default values, we do at least get some further assurances when using TypeScript:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"380\" height=\"115\" data-attachment-id=\"1435\" data-permalink=\"https:\/\/codereviewvideos.com\/react-usereducer-typescript-example\/reset-basket-set-state-typescript\/#main\" data-orig-file=\"https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/11\/reset-basket-set-state-typescript.png?fit=380%2C115&amp;ssl=1\" data-orig-size=\"380,115\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"reset-basket-set-state-typescript\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/11\/reset-basket-set-state-typescript.png?fit=380%2C115&amp;ssl=1\" src=\"https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/11\/reset-basket-set-state-typescript.png?resize=380%2C115&#038;ssl=1\" alt=\"\" class=\"wp-image-1435\" srcset=\"https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/11\/reset-basket-set-state-typescript.png?w=380&amp;ssl=1 380w, https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/11\/reset-basket-set-state-typescript.png?resize=300%2C91&amp;ssl=1 300w\" sizes=\"auto, (max-width: 380px) 100vw, 380px\" \/><\/figure>\n<\/div>\n\n\n<p>We&#8217;re still responsible for setting the values, but TypeScript at least ensures they match the types we provided in the original calls to <code>useState<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-24\" data-shcb-language-name=\"TypeScript\" data-shcb-language-slug=\"typescript\"><span><code class=\"hljs language-typescript\">  <span class=\"hljs-keyword\">const<\/span> &#091;basket, setBasket] = useState&lt;Product&#091;]&gt;(&#091;]);\n  <span class=\"hljs-keyword\">const<\/span> &#091;total, setTotal] = useState&lt;<span class=\"hljs-built_in\">number<\/span>&gt;(<span class=\"hljs-number\">0<\/span>);<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-24\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">TypeScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">typescript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p><code>basket<\/code> must be an empty array, or an array of things that look like <code>Product<\/code>. <\/p>\n\n\n\n<p>And likewise, <code>total<\/code> can only be a number.<\/p>\n\n\n\n<p>But &#8230; any number. We need not reset the <code>total<\/code> to <code>0<\/code> like we did in the original call. We still have to keep those two in sync. It sounds so trivial, but this is a legitimate source of bugs on larger projects. <\/p>\n\n\n\n<h5 class=\"wp-block-heading\">Re-use Your Type Definitions: Indexed Access Types<\/h5>\n\n\n\n<p>This is one I see frequently out there in the real world:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-25\" data-shcb-language-name=\"TypeScript\" data-shcb-language-slug=\"typescript\"><span><code class=\"hljs language-typescript shcb-code-table\"><mark class='shcb-loc'><span><span class=\"hljs-keyword\">const<\/span> isProductInBasket = (productId: <span class=\"hljs-built_in\">number<\/span>): <span class=\"hljs-function\"><span class=\"hljs-params\">boolean<\/span> =&gt;<\/span> {\n<\/span><\/mark><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">return<\/span> basket.some(<span class=\"hljs-function\">(<span class=\"hljs-params\"><span class=\"hljs-params\">product<\/span><\/span>) =&gt;<\/span> product.id === productId);\n<\/span><\/span><span class='shcb-loc'><span>};\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-comment\">\/\/ versus<\/span>\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><mark class='shcb-loc'><span><span class=\"hljs-keyword\">const<\/span> isProductInBasket = (productId: Product&#091;<span class=\"hljs-string\">'id'<\/span>]): <span class=\"hljs-function\"><span class=\"hljs-params\">boolean<\/span> =&gt;<\/span> {\n<\/span><\/mark><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">return<\/span> basket.some(<span class=\"hljs-function\">(<span class=\"hljs-params\"><span class=\"hljs-params\">product<\/span><\/span>) =&gt;<\/span> product.id === productId);\n<\/span><\/span><span class='shcb-loc'><span>};\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-25\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">TypeScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">typescript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>The two lines are functionally identical.<\/p>\n\n\n\n<p>Our <code>Product<\/code> interface defines <code>id<\/code> as a <code>number<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-26\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">interface<\/span> <span class=\"hljs-selector-tag\">Product<\/span> {\n  <span class=\"hljs-attribute\">id<\/span>: number;\n  <span class=\"hljs-attribute\">name<\/span>: string;\n  <span class=\"hljs-attribute\">price<\/span>: number;\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-26\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>And either give us type safety:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"209\" data-attachment-id=\"1437\" data-permalink=\"https:\/\/codereviewvideos.com\/react-usereducer-typescript-example\/type-safety-using-index-access-type\/#main\" data-orig-file=\"https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/11\/type-safety-using-index-access-type.png?fit=1105%2C225&amp;ssl=1\" data-orig-size=\"1105,225\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"type-safety-using-index-access-type\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/11\/type-safety-using-index-access-type.png?fit=1024%2C209&amp;ssl=1\" src=\"https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/11\/type-safety-using-index-access-type.png?resize=1024%2C209&#038;ssl=1\" alt=\"typescript index access type\" class=\"wp-image-1437\" srcset=\"https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/11\/type-safety-using-index-access-type.png?resize=1024%2C209&amp;ssl=1 1024w, https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/11\/type-safety-using-index-access-type.png?resize=300%2C61&amp;ssl=1 300w, https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/11\/type-safety-using-index-access-type.png?resize=768%2C156&amp;ssl=1 768w, https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/11\/type-safety-using-index-access-type.png?w=1105&amp;ssl=1 1105w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>But we already defined the type of <code>id<\/code> on our <code>Produc<\/code>t interface. By defining the parameter of <code>isProductInBasket<\/code> as <code>number<\/code>, we have disconnected the two concepts. <\/p>\n\n\n\n<p>Sure, they are both <code>number<\/code> &#8230; now. But what about in the future? What if we swap to a <code>uuid<\/code> or something? Well, now we need to update two places, or hope that our unit tests (which we do have, right?) catch the issue. <\/p>\n\n\n\n<p>It sounds so trivial. However it, again, is a legitimate source of real world problems. <\/p>\n\n\n\n<p>TypeScript calls this concept an <a href=\"https:\/\/codereviewvideos.com\/typescript-indexed-access-type\" target=\"_blank\" rel=\"noreferrer noopener\">Indexed Access Type<\/a>. Why not use it?<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Refactoring To useReducer<\/h3>\n\n\n\n<p>We&#8217;re almost there now.<\/p>\n\n\n\n<p>I&#8217;m going to skip the JavaScript version of this component now, because in reality I haven&#8217;t made a plain JSX component in a very long time and have no intention of going back there when TypeScript exists.<\/p>\n\n\n\n<p>We&#8217;ve covered the <code>useState<\/code> version of the <code>ShoppingBasket<\/code>. Now let&#8217;s refactor the code to retain the exact same behaviour, but make use of the <code>useReducer<\/code> hook. <\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-27\" data-shcb-language-name=\"TypeScript\" data-shcb-language-slug=\"typescript\"><span><code class=\"hljs language-typescript\"><span class=\"hljs-comment\">\/\/ src\/ShoppingBasket.tsx<\/span>\n\n<span class=\"hljs-keyword\">import<\/span> React, { useReducer } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"react\"<\/span>;\n\n<span class=\"hljs-keyword\">interface<\/span> Product {\n  id: <span class=\"hljs-built_in\">number<\/span>;\n  name: <span class=\"hljs-built_in\">string<\/span>;\n  price: <span class=\"hljs-built_in\">number<\/span>;\n}\n\n<span class=\"hljs-keyword\">interface<\/span> State {\n  basket: Product&#091;];\n  total: <span class=\"hljs-built_in\">number<\/span>;\n}\n\n<span class=\"hljs-keyword\">type<\/span> Action =\n  | { <span class=\"hljs-keyword\">type<\/span>: <span class=\"hljs-string\">\"ADD_TO_BASKET\"<\/span>; product: Product }\n  | { <span class=\"hljs-keyword\">type<\/span>: <span class=\"hljs-string\">\"REMOVE_FROM_BASKET\"<\/span>; product: Product }\n  | { <span class=\"hljs-keyword\">type<\/span>: <span class=\"hljs-string\">\"RESET_BASKET\"<\/span> };\n\n<span class=\"hljs-keyword\">const<\/span> initialState: State = {\n  basket: &#091;],\n  total: <span class=\"hljs-number\">0<\/span>,\n};\n\n<span class=\"hljs-keyword\">const<\/span> reducer = (state: State, action: Action): <span class=\"hljs-function\"><span class=\"hljs-params\">State<\/span> =&gt;<\/span> {\n  <span class=\"hljs-keyword\">switch<\/span> (action.type) {\n    <span class=\"hljs-keyword\">case<\/span> <span class=\"hljs-string\">\"ADD_TO_BASKET\"<\/span>:\n      <span class=\"hljs-keyword\">return<\/span> {\n        basket: &#091;...state.basket, action.product],\n        total: state.total + action.product.price,\n      };\n    <span class=\"hljs-keyword\">case<\/span> <span class=\"hljs-string\">\"REMOVE_FROM_BASKET\"<\/span>:\n      <span class=\"hljs-keyword\">const<\/span> updatedBasket = state.basket.filter(\n        <span class=\"hljs-function\">(<span class=\"hljs-params\"><span class=\"hljs-params\">item<\/span><\/span>) =&gt;<\/span> item.id !== action.product.id,\n      );\n      <span class=\"hljs-keyword\">return<\/span> {\n        basket: updatedBasket,\n        total: state.total - action.product.price,\n      };\n    <span class=\"hljs-keyword\">case<\/span> <span class=\"hljs-string\">\"RESET_BASKET\"<\/span>:\n      <span class=\"hljs-keyword\">return<\/span> initialState;\n    <span class=\"hljs-keyword\">default<\/span>:\n      <span class=\"hljs-keyword\">return<\/span> state;\n  }\n};\n\n<span class=\"hljs-keyword\">const<\/span> isProductInBasket = (\n  basket: State&#091;<span class=\"hljs-string\">\"basket\"<\/span>],\n  productId: Product&#091;<span class=\"hljs-string\">\"id\"<\/span>],\n): <span class=\"hljs-function\"><span class=\"hljs-params\">boolean<\/span> =&gt;<\/span> {\n  <span class=\"hljs-keyword\">return<\/span> basket.some(<span class=\"hljs-function\">(<span class=\"hljs-params\"><span class=\"hljs-params\">product<\/span><\/span>) =&gt;<\/span> product.id === productId);\n};\n\n<span class=\"hljs-keyword\">const<\/span> productVariations: Product&#091;] = &#091;\n  { id: <span class=\"hljs-number\">1<\/span>, name: <span class=\"hljs-string\">\"Product 1\"<\/span>, price: <span class=\"hljs-number\">10<\/span> },\n  { id: <span class=\"hljs-number\">2<\/span>, name: <span class=\"hljs-string\">\"Product 2\"<\/span>, price: <span class=\"hljs-number\">5<\/span> },\n  { id: <span class=\"hljs-number\">3<\/span>, name: <span class=\"hljs-string\">\"Product 3\"<\/span>, price: <span class=\"hljs-number\">15<\/span> },\n  { id: <span class=\"hljs-number\">4<\/span>, name: <span class=\"hljs-string\">\"Product 4\"<\/span>, price: <span class=\"hljs-number\">8<\/span> },\n  { id: <span class=\"hljs-number\">5<\/span>, name: <span class=\"hljs-string\">\"Product 5\"<\/span>, price: <span class=\"hljs-number\">12<\/span> },\n];\n\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">ShoppingBasket<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> &#091;state, dispatch] = useReducer(reducer, initialState);\n\n  <span class=\"hljs-keyword\">return<\/span> (\n    &lt;div&gt;\n      &lt;h2&gt;Shopping Basket&lt;<span class=\"hljs-regexp\">\/h2&gt;\n      &lt;ul&gt;\n        {state.basket.map((product) =&gt; (\n          &lt;li key={product.id}&gt;\n            {product.name} - \u00a3{product.price}\n            &lt;button\n              onClick={() =&gt; dispatch({ type: \"REMOVE_FROM_BASKET\", product })}\n            &gt;\n              Remove\n            &lt;\/<\/span>button&gt;\n          &lt;<span class=\"hljs-regexp\">\/li&gt;\n        ))}\n      &lt;\/u<\/span>l&gt;\n      &lt;p&gt;Total: \u00a3{state.total}&lt;<span class=\"hljs-regexp\">\/p&gt;\n      &lt;div&gt;\n        {productVariations.map((product) =&gt; (\n          &lt;button\n            key={product.id}\n            onClick={() =&gt; dispatch({ type: \"ADD_TO_BASKET\", product })}\n            disabled={isProductInBasket(state.basket, product.id)}\n          &gt;\n            Add {product.name}\n          &lt;\/<\/span>button&gt;\n        ))}\n        &lt;button\n          onClick={<span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> dispatch({ <span class=\"hljs-keyword\">type<\/span>: <span class=\"hljs-string\">\"RESET_BASKET\"<\/span> })}\n        &gt;\n          Reset Basket\n        &lt;<span class=\"hljs-regexp\">\/button&gt;\n      &lt;\/<\/span>div&gt;\n    &lt;<span class=\"hljs-regexp\">\/div&gt;\n  );\n}\n\nexport default ShoppingBasket;\n<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-27\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">TypeScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">typescript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>There are two things that jump out at a glance:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>There is a <strong>lot<\/strong> of setup \/ pre-stuff<\/li>\n\n\n\n<li>The actual component rendering logic is now really quite slim<\/li>\n<\/ol>\n\n\n\n<p>So yeah, we jumped up by about 30 lines. <\/p>\n\n\n\n<p>Was it worth it?<\/p>\n\n\n\n<p>I&#8217;d say so. And here&#8217;s why I think that.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Type Safety<\/h4>\n\n\n\n<p>We&#8217;ve explicitly described our component&#8217;s types:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-28\" data-shcb-language-name=\"TypeScript\" data-shcb-language-slug=\"typescript\"><span><code class=\"hljs language-typescript\"><span class=\"hljs-keyword\">interface<\/span> Product {\n  id: <span class=\"hljs-built_in\">number<\/span>;\n  name: <span class=\"hljs-built_in\">string<\/span>;\n  price: <span class=\"hljs-built_in\">number<\/span>;\n}\n\n<span class=\"hljs-keyword\">interface<\/span> State {\n  basket: Product&#091;];\n  total: <span class=\"hljs-built_in\">number<\/span>;\n}\n\n<span class=\"hljs-keyword\">type<\/span> Action =\n  | { <span class=\"hljs-keyword\">type<\/span>: <span class=\"hljs-string\">\"ADD_TO_BASKET\"<\/span>; product: Product }\n  | { <span class=\"hljs-keyword\">type<\/span>: <span class=\"hljs-string\">\"REMOVE_FROM_BASKET\"<\/span>; product: Product }\n  | { <span class=\"hljs-keyword\">type<\/span>: <span class=\"hljs-string\">\"RESET_BASKET\"<\/span> };<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-28\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">TypeScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">typescript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Throughout this post we&#8217;ve covered all of this information. The only addition is the inclusion of <code>product<\/code> in two of our <code>Action<\/code>s. <\/p>\n\n\n\n<p>As I said earlier, our types are <strong>ours<\/strong>. <\/p>\n\n\n\n<p>They represent our things. We can change them however we like, and however we need. <\/p>\n\n\n\n<p>To add or remove a product to or from the basket, we need to say which <code>Product<\/code> we are working with. Now that information is captured in the specific <code>Action<\/code>. This means if we want to add a product to the basket, we must provide the product we are adding. <\/p>\n\n\n\n<p>Makes a lot of sense. <\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Declare And ReUse Initial State<\/h4>\n\n\n\n<p>One of my big gripes with previous iterations of this component was the need to set and reset the initial state. <\/p>\n\n\n\n<p>Now we define the components initial state only once:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-29\" data-shcb-language-name=\"TypeScript\" data-shcb-language-slug=\"typescript\"><span><code class=\"hljs language-typescript\"><span class=\"hljs-keyword\">const<\/span> initialState: State = {\n  basket: &#091;],\n  total: <span class=\"hljs-number\">0<\/span>,\n};<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-29\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">TypeScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">typescript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>But we make use of it twice.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-30\" data-shcb-language-name=\"TypeScript\" data-shcb-language-slug=\"typescript\"><span><code class=\"hljs language-typescript shcb-code-table\"><span class='shcb-loc'><span><span class=\"hljs-keyword\">const<\/span> initialState: State = {\n<\/span><\/span><span class='shcb-loc'><span>  basket: &#091;],\n<\/span><\/span><span class='shcb-loc'><span>  total: <span class=\"hljs-number\">0<\/span>,\n<\/span><\/span><span class='shcb-loc'><span>};\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">const<\/span> reducer = (state: State, action: Action): <span class=\"hljs-function\"><span class=\"hljs-params\">State<\/span> =&gt;<\/span> {\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">switch<\/span> (action.type) {\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-comment\">\/\/ ...<\/span>\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-keyword\">case<\/span> <span class=\"hljs-string\">\"RESET_BASKET\"<\/span>:\n<\/span><\/span><mark class='shcb-loc'><span>      <span class=\"hljs-keyword\">return<\/span> initialState;\n<\/span><\/mark><span class='shcb-loc'><span>    <span class=\"hljs-keyword\">default<\/span>:\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-keyword\">return<\/span> state;\n<\/span><\/span><span class='shcb-loc'><span>  }\n<\/span><\/span><span class='shcb-loc'><span>};\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-comment\">\/\/ ...<\/span>\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">ShoppingBasket<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n<\/span><\/span><mark class='shcb-loc'><span>  <span class=\"hljs-keyword\">const<\/span> &#091;state, dispatch] = useReducer(reducer, initialState);\n<\/span><\/mark><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-30\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">TypeScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">typescript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>It&#8217;s a small change, but it helps reduce bugs. Don&#8217;t repeat yourself, and all that. <\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Our State Is Highly Unit Testable<\/h4>\n\n\n\n<p>For me, being a test loving saddo, the biggest win is the fact that the components state is a highly testable pure function:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-31\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">const<\/span> reducer = (state: State, <span class=\"hljs-attr\">action<\/span>: Action): <span class=\"hljs-function\"><span class=\"hljs-params\">State<\/span> =&gt;<\/span> {\n  <span class=\"hljs-keyword\">switch<\/span> (action.type) {\n    <span class=\"hljs-keyword\">case<\/span> <span class=\"hljs-string\">\"ADD_TO_BASKET\"<\/span>:\n      <span class=\"hljs-keyword\">return<\/span> {\n        <span class=\"hljs-attr\">basket<\/span>: &#091;...state.basket, action.product],\n        <span class=\"hljs-attr\">total<\/span>: state.total + action.product.price,\n      };\n    <span class=\"hljs-keyword\">case<\/span> <span class=\"hljs-string\">\"REMOVE_FROM_BASKET\"<\/span>:\n      <span class=\"hljs-keyword\">const<\/span> updatedBasket = state.basket.filter(\n        <span class=\"hljs-function\">(<span class=\"hljs-params\">item<\/span>) =&gt;<\/span> item.id !== action.product.id,\n      );\n      <span class=\"hljs-keyword\">return<\/span> {\n        <span class=\"hljs-attr\">basket<\/span>: updatedBasket,\n        <span class=\"hljs-attr\">total<\/span>: state.total - action.product.price,\n      };\n    <span class=\"hljs-keyword\">case<\/span> <span class=\"hljs-string\">\"RESET_BASKET\"<\/span>:\n      <span class=\"hljs-keyword\">return<\/span> initialState;\n    <span class=\"hljs-keyword\">default<\/span>:\n      <span class=\"hljs-keyword\">return<\/span> state;\n  }\n};<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-31\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>There&#8217;s something so satisfying about testing a pure function. Which is to say if the function is given the same arguments, it always returns the same result. <\/p>\n\n\n\n<p><code>1 + 1 = 2<\/code><\/p>\n\n\n\n<p>There&#8217;s no API calls firing off or reliance on some external state that may have changed leading to a different result. <\/p>\n\n\n\n<p>Everything is self contained here. You could extract this logic out to a separate file, unit test it and import it back in. Confidence. I love it. <\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Monkey Jungle<\/h4>\n\n\n\n<p>A lot of this stuff is opinion.<\/p>\n\n\n\n<p>Here&#8217;s another.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-32\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">const<\/span> isProductInBasket = (\n  basket: State&#091;<span class=\"hljs-string\">\"basket\"<\/span>],\n  <span class=\"hljs-attr\">productId<\/span>: Product&#091;<span class=\"hljs-string\">\"id\"<\/span>],\n): <span class=\"hljs-function\"><span class=\"hljs-params\">boolean<\/span> =&gt;<\/span> {\n  <span class=\"hljs-keyword\">return<\/span> basket.some(<span class=\"hljs-function\">(<span class=\"hljs-params\">product<\/span>) =&gt;<\/span> product.id === productId);\n};<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-32\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Does that need extracting?<\/p>\n\n\n\n<p>I would say it makes it easier to unit test, so yes, extract it.<\/p>\n\n\n\n<p>Another way to write this would be to have it inside the component function itself, and get access to <code>state<\/code> via closure:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-33\" data-shcb-language-name=\"TypeScript\" data-shcb-language-slug=\"typescript\"><span><code class=\"hljs language-typescript\"><span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">ShoppingBasket<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> &#091;state, dispatch] = useReducer(reducer, initialState);\n\n  <span class=\"hljs-keyword\">const<\/span> isProductInBasket = (productId: <span class=\"hljs-built_in\">number<\/span>): <span class=\"hljs-function\"><span class=\"hljs-params\">boolean<\/span> =&gt;<\/span> {\n    <span class=\"hljs-keyword\">return<\/span> state.basket.some(<span class=\"hljs-function\">(<span class=\"hljs-params\"><span class=\"hljs-params\">product<\/span><\/span>) =&gt;<\/span> product.id === productId);\n  };<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-33\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">TypeScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">typescript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>My argument against this is that firstly, you don&#8217;t need the full <code>state<\/code> object to figure out whether a product is in the basket. <\/p>\n\n\n\n<p>And secondly, containing the <code>isProductInBasket<\/code> function inside the <code>ShoppingBasket<\/code> makes it really hard to test in isolation. <\/p>\n\n\n\n<p>Extracting the function out, and only passing in the specific bit of state you need to get the outcome is preferable (again, imho):<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-34\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-code-table\"><span class='shcb-loc'><span><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\">  <span class=\"hljs-attr\">key<\/span>=<span class=\"hljs-string\">{product.id}<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\">  <span class=\"hljs-attr\">onClick<\/span>=<span class=\"hljs-string\">{()<\/span> =&gt;<\/span> dispatch({type: \"ADD_TO_BASKET\", product})}\n<\/span><\/span><mark class='shcb-loc'><span>  disabled={isProductInBasket(product.id)}\n<\/span><\/mark><span class='shcb-loc'><span>&gt;\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span>\/\/ versus\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\">  <span class=\"hljs-attr\">key<\/span>=<span class=\"hljs-string\">{product.id}<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\">  <span class=\"hljs-attr\">onClick<\/span>=<span class=\"hljs-string\">{()<\/span> =&gt;<\/span> dispatch({ type: \"ADD_TO_BASKET\", product })}\n<\/span><\/span><mark class='shcb-loc'><span>  disabled={isProductInBasket(state.basket, product.id)}\n<\/span><\/mark><span class='shcb-loc'><span>&gt;\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-34\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Why pass the entire state (the entire <em>jungle<\/em>) when you only need the basket array (the <em>monkey<\/em>)? <\/p>\n\n\n\n<p>It just makes setting up your tests that much harder. <\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Wrap Up<\/h2>\n\n\n\n<p>That&#8217;s my take on why I prefer <code>useReducer<\/code> over <code>useState<\/code> in almost any component of real world complexity. <\/p>\n\n\n\n<p>Of course your mileage my vary, these are only my opinions, and I&#8217;m always open to improving or changing, if a better way presents itself. <\/p>\n\n\n\n<p>My experience has shown me that some developers tend to shy away from <code>useReducer<\/code> in favour of <code>useState<\/code> as they think the <code>useReducer<\/code> approach is more complex. I hope I have gone some way to convince you otherwise.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Of all the hooks available in React, useReducer is easily my favourite. It&#8217;s nice to be able to solve simple problems with useState, but in component&#8217;s with even a smaller amount of complexity than can be solved with a boolean state value, I tend to favour useReducer. Let&#8217;s dig in, see some examples, and find &#8230; <a title=\"React useReducer TypeScript Example\" class=\"read-more\" href=\"https:\/\/codereviewvideos.com\/react-usereducer-typescript-example\/\" aria-label=\"Read more about React useReducer TypeScript Example\">Read more<\/a><\/p>\n","protected":false},"author":1,"featured_media":1409,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"cybocfi_hide_featured_image":"yes","_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[29],"tags":[31,19,20],"class_list":["post-1406","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-javascript-typescript-nodejs","tag-javascript","tag-react","tag-typescript"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.4 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>React useReducer TypeScript Example - Code Review Videos<\/title>\n<meta name=\"description\" content=\"Using two examples, lets refactor from useState to useReducer in React for managing complex component state.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/codereviewvideos.com\/react-usereducer-typescript-example\/\" \/>\n<meta property=\"og:locale\" content=\"en_GB\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"React useReducer TypeScript Example - Code Review Videos\" \/>\n<meta property=\"og:description\" content=\"Using two examples, lets refactor from useState to useReducer in React for managing complex component state.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/codereviewvideos.com\/react-usereducer-typescript-example\/\" \/>\n<meta property=\"og:site_name\" content=\"Code Review Videos\" \/>\n<meta property=\"article:published_time\" content=\"2023-11-17T07:55:00+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/11\/webstorm-use-reducer-typescript-example.png?fit=810%2C1314&ssl=1\" \/>\n\t<meta property=\"og:image:width\" content=\"810\" \/>\n\t<meta property=\"og:image:height\" content=\"1314\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Chris\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Chris\" \/>\n\t<meta name=\"twitter:label2\" content=\"Estimated reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"13 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/codereviewvideos.com\\\/react-usereducer-typescript-example\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/codereviewvideos.com\\\/react-usereducer-typescript-example\\\/\"},\"author\":{\"name\":\"Chris\",\"@id\":\"https:\\\/\\\/codereviewvideos.com\\\/#\\\/schema\\\/person\\\/4c9762075e6fb93b47f1cd87ed78fe31\"},\"headline\":\"React useReducer TypeScript Example\",\"datePublished\":\"2023-11-17T07:55:00+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/codereviewvideos.com\\\/react-usereducer-typescript-example\\\/\"},\"wordCount\":2548,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/codereviewvideos.com\\\/#\\\/schema\\\/person\\\/4c9762075e6fb93b47f1cd87ed78fe31\"},\"image\":{\"@id\":\"https:\\\/\\\/codereviewvideos.com\\\/react-usereducer-typescript-example\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/i0.wp.com\\\/codereviewvideos.com\\\/wp-content\\\/uploads\\\/2023\\\/11\\\/webstorm-use-reducer-typescript-example.png?fit=810%2C1314&ssl=1\",\"keywords\":[\"javascript\",\"react\",\"typescript\"],\"articleSection\":[\"JavaScript &amp; TypeScript\"],\"inLanguage\":\"en-GB\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/codereviewvideos.com\\\/react-usereducer-typescript-example\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/codereviewvideos.com\\\/react-usereducer-typescript-example\\\/\",\"url\":\"https:\\\/\\\/codereviewvideos.com\\\/react-usereducer-typescript-example\\\/\",\"name\":\"React useReducer TypeScript Example - Code Review Videos\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/codereviewvideos.com\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/codereviewvideos.com\\\/react-usereducer-typescript-example\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/codereviewvideos.com\\\/react-usereducer-typescript-example\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/i0.wp.com\\\/codereviewvideos.com\\\/wp-content\\\/uploads\\\/2023\\\/11\\\/webstorm-use-reducer-typescript-example.png?fit=810%2C1314&ssl=1\",\"datePublished\":\"2023-11-17T07:55:00+00:00\",\"description\":\"Using two examples, lets refactor from useState to useReducer in React for managing complex component state.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/codereviewvideos.com\\\/react-usereducer-typescript-example\\\/#breadcrumb\"},\"inLanguage\":\"en-GB\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/codereviewvideos.com\\\/react-usereducer-typescript-example\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/codereviewvideos.com\\\/react-usereducer-typescript-example\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/codereviewvideos.com\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"React useReducer TypeScript Example\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/codereviewvideos.com\\\/#website\",\"url\":\"https:\\\/\\\/codereviewvideos.com\\\/\",\"name\":\"Code Review Videos\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\\\/\\\/codereviewvideos.com\\\/#\\\/schema\\\/person\\\/4c9762075e6fb93b47f1cd87ed78fe31\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/codereviewvideos.com\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-GB\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\\\/\\\/codereviewvideos.com\\\/#\\\/schema\\\/person\\\/4c9762075e6fb93b47f1cd87ed78fe31\",\"name\":\"Chris\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-GB\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/17fa68e8f9bd902efa9ec761b6200d3a6b7d052ec05ed098efd0cca9c37e238b?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/17fa68e8f9bd902efa9ec761b6200d3a6b7d052ec05ed098efd0cca9c37e238b?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/17fa68e8f9bd902efa9ec761b6200d3a6b7d052ec05ed098efd0cca9c37e238b?s=96&d=mm&r=g\",\"caption\":\"Chris\"},\"logo\":{\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/17fa68e8f9bd902efa9ec761b6200d3a6b7d052ec05ed098efd0cca9c37e238b?s=96&d=mm&r=g\"},\"sameAs\":[\"https:\\\/\\\/codereviewvideos.com\"],\"url\":\"https:\\\/\\\/codereviewvideos.com\\\/author\\\/crv_v5_admin\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"React useReducer TypeScript Example - Code Review Videos","description":"Using two examples, lets refactor from useState to useReducer in React for managing complex component state.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/codereviewvideos.com\/react-usereducer-typescript-example\/","og_locale":"en_GB","og_type":"article","og_title":"React useReducer TypeScript Example - Code Review Videos","og_description":"Using two examples, lets refactor from useState to useReducer in React for managing complex component state.","og_url":"https:\/\/codereviewvideos.com\/react-usereducer-typescript-example\/","og_site_name":"Code Review Videos","article_published_time":"2023-11-17T07:55:00+00:00","og_image":[{"width":810,"height":1314,"url":"https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/11\/webstorm-use-reducer-typescript-example.png?fit=810%2C1314&ssl=1","type":"image\/png"}],"author":"Chris","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Chris","Estimated reading time":"13 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/codereviewvideos.com\/react-usereducer-typescript-example\/#article","isPartOf":{"@id":"https:\/\/codereviewvideos.com\/react-usereducer-typescript-example\/"},"author":{"name":"Chris","@id":"https:\/\/codereviewvideos.com\/#\/schema\/person\/4c9762075e6fb93b47f1cd87ed78fe31"},"headline":"React useReducer TypeScript Example","datePublished":"2023-11-17T07:55:00+00:00","mainEntityOfPage":{"@id":"https:\/\/codereviewvideos.com\/react-usereducer-typescript-example\/"},"wordCount":2548,"commentCount":0,"publisher":{"@id":"https:\/\/codereviewvideos.com\/#\/schema\/person\/4c9762075e6fb93b47f1cd87ed78fe31"},"image":{"@id":"https:\/\/codereviewvideos.com\/react-usereducer-typescript-example\/#primaryimage"},"thumbnailUrl":"https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/11\/webstorm-use-reducer-typescript-example.png?fit=810%2C1314&ssl=1","keywords":["javascript","react","typescript"],"articleSection":["JavaScript &amp; TypeScript"],"inLanguage":"en-GB","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/codereviewvideos.com\/react-usereducer-typescript-example\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/codereviewvideos.com\/react-usereducer-typescript-example\/","url":"https:\/\/codereviewvideos.com\/react-usereducer-typescript-example\/","name":"React useReducer TypeScript Example - Code Review Videos","isPartOf":{"@id":"https:\/\/codereviewvideos.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/codereviewvideos.com\/react-usereducer-typescript-example\/#primaryimage"},"image":{"@id":"https:\/\/codereviewvideos.com\/react-usereducer-typescript-example\/#primaryimage"},"thumbnailUrl":"https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/11\/webstorm-use-reducer-typescript-example.png?fit=810%2C1314&ssl=1","datePublished":"2023-11-17T07:55:00+00:00","description":"Using two examples, lets refactor from useState to useReducer in React for managing complex component state.","breadcrumb":{"@id":"https:\/\/codereviewvideos.com\/react-usereducer-typescript-example\/#breadcrumb"},"inLanguage":"en-GB","potentialAction":[{"@type":"ReadAction","target":["https:\/\/codereviewvideos.com\/react-usereducer-typescript-example\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/codereviewvideos.com\/react-usereducer-typescript-example\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/codereviewvideos.com\/"},{"@type":"ListItem","position":2,"name":"React useReducer TypeScript Example"}]},{"@type":"WebSite","@id":"https:\/\/codereviewvideos.com\/#website","url":"https:\/\/codereviewvideos.com\/","name":"Code Review Videos","description":"","publisher":{"@id":"https:\/\/codereviewvideos.com\/#\/schema\/person\/4c9762075e6fb93b47f1cd87ed78fe31"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/codereviewvideos.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-GB"},{"@type":["Person","Organization"],"@id":"https:\/\/codereviewvideos.com\/#\/schema\/person\/4c9762075e6fb93b47f1cd87ed78fe31","name":"Chris","image":{"@type":"ImageObject","inLanguage":"en-GB","@id":"https:\/\/secure.gravatar.com\/avatar\/17fa68e8f9bd902efa9ec761b6200d3a6b7d052ec05ed098efd0cca9c37e238b?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/17fa68e8f9bd902efa9ec761b6200d3a6b7d052ec05ed098efd0cca9c37e238b?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/17fa68e8f9bd902efa9ec761b6200d3a6b7d052ec05ed098efd0cca9c37e238b?s=96&d=mm&r=g","caption":"Chris"},"logo":{"@id":"https:\/\/secure.gravatar.com\/avatar\/17fa68e8f9bd902efa9ec761b6200d3a6b7d052ec05ed098efd0cca9c37e238b?s=96&d=mm&r=g"},"sameAs":["https:\/\/codereviewvideos.com"],"url":"https:\/\/codereviewvideos.com\/author\/crv_v5_admin\/"}]}},"jetpack_featured_media_url":"https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/11\/webstorm-use-reducer-typescript-example.png?fit=810%2C1314&ssl=1","jetpack_sharing_enabled":true,"jetpack_likes_enabled":true,"jetpack-related-posts":[{"id":1383,"url":"https:\/\/codereviewvideos.com\/react-show-more-show-less-with-multiple-paragraphs\/","url_meta":{"origin":1406,"position":0},"title":"React: Show More \/ Show Less With Multiple Paragraphs","author":"Chris","date":"10 November 2023","format":false,"excerpt":"In this post I will show you a way to create a unit tested React component that allows you to pass either a plain string, or one or more <p>text goes here<\/p> tags, and then render out only the first X words. When the word limit is hit, a 'Show\u2026","rel":"","context":"In &quot;JavaScript &amp; TypeScript&quot;","block_context":{"text":"JavaScript &amp; TypeScript","link":"https:\/\/codereviewvideos.com\/category\/javascript-typescript-nodejs\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/11\/Screenshot-from-2023-11-03-15-21-26.png?resize=350%2C200&ssl=1","width":350,"height":200},"classes":[]},{"id":1581,"url":"https:\/\/codereviewvideos.com\/nextjs-14-crud-forms-example\/","url_meta":{"origin":1406,"position":1},"title":"NextJS 14 CRUD Forms Example","author":"Chris","date":"6 January 2024","format":false,"excerpt":"I recently had to do a proof of concept site using NextJS 14. I hadn't used NextJS since version 11, and who knew how much could change in 3 major versions? The big change is the use of Server Actions, and then the App Router \/ \/app directory, as opposed\u2026","rel":"","context":"In &quot;JavaScript &amp; TypeScript&quot;","block_context":{"text":"JavaScript &amp; TypeScript","link":"https:\/\/codereviewvideos.com\/category\/javascript-typescript-nodejs\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2024\/01\/next-js-crud-forms-example.png?fit=720%2C480&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2024\/01\/next-js-crud-forms-example.png?fit=720%2C480&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2024\/01\/next-js-crud-forms-example.png?fit=720%2C480&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2024\/01\/next-js-crud-forms-example.png?fit=720%2C480&ssl=1&resize=700%2C400 2x"},"classes":[]},{"id":1887,"url":"https:\/\/codereviewvideos.com\/what-if-your-object-could-be-more-than-one-type-in-typescript\/","url_meta":{"origin":1406,"position":2},"title":"What If Your Object Could Be More Than One Type in TypeScript?","author":"Chris","date":"16 October 2024","format":false,"excerpt":"In TypeScript, imagine you have a situation where you have an object that could be one of several different types. How do you explain to TypeScript that the object you are working with is a specific type? Not very clear? OK. Let's see some code, and then it will likely\u2026","rel":"","context":"In &quot;JavaScript &amp; TypeScript&quot;","block_context":{"text":"JavaScript &amp; TypeScript","link":"https:\/\/codereviewvideos.com\/category\/javascript-typescript-nodejs\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2024\/10\/what-if-your-object-could-be-more-than-one-type-in-typescript.png?fit=800%2C800&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2024\/10\/what-if-your-object-could-be-more-than-one-type-in-typescript.png?fit=800%2C800&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2024\/10\/what-if-your-object-could-be-more-than-one-type-in-typescript.png?fit=800%2C800&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2024\/10\/what-if-your-object-could-be-more-than-one-type-in-typescript.png?fit=800%2C800&ssl=1&resize=700%2C400 2x"},"classes":[]},{"id":1351,"url":"https:\/\/codereviewvideos.com\/typing-req-query-in-express-with-typescript\/","url_meta":{"origin":1406,"position":3},"title":"Typing req.query In Express With TypeScript","author":"Chris","date":"30 October 2023","format":false,"excerpt":"If you're using TypeScript with Express, you may well hit on TS2339: Property 'whatever' does not exist on type 'RequestQuery'. It's actually pretty easy to solve. Perhaps more frustrating than anything, as you may well have lots of examples of this problem, especially if migrating an older project from JavaScript,\u2026","rel":"","context":"In &quot;JavaScript &amp; TypeScript&quot;","block_context":{"text":"JavaScript &amp; TypeScript","link":"https:\/\/codereviewvideos.com\/category\/javascript-typescript-nodejs\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/10\/typescript-request-type-for-express.png?fit=764%2C469&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/10\/typescript-request-type-for-express.png?fit=764%2C469&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/10\/typescript-request-type-for-express.png?fit=764%2C469&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/10\/typescript-request-type-for-express.png?fit=764%2C469&ssl=1&resize=700%2C400 2x"},"classes":[]},{"id":1262,"url":"https:\/\/codereviewvideos.com\/how-i-fixed-weve-found-2-cypress-configuration-files-named-cypress-config-ts-cypress-config-js\/","url_meta":{"origin":1406,"position":4},"title":"How I Fixed: We&#8217;ve found\u00a02\u00a0Cypress configuration files named\u00a0cypress.config.ts, cypress.config.js","author":"Chris","date":"7 October 2023","format":false,"excerpt":"If you're using Cypress with TypeScript in your project, it's possible you may encounter the following error message when trying to run Cypress: Could not load a Cypress configuration file because there are multiple matches. We've found 2 Cypress configuration files named cypress.config.ts, cypress.config.js at the location below: \/home\/chris\/Development\/cypress-validate-dropdown-options-example Please\u2026","rel":"","context":"In &quot;How I Fixed&quot;","block_context":{"text":"How I Fixed","link":"https:\/\/codereviewvideos.com\/category\/how-i-fixed\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/10\/found-2-cypress-configuration-files-named-cypress-config-ts-cypress-config-js.png?fit=749%2C662&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/10\/found-2-cypress-configuration-files-named-cypress-config-ts-cypress-config-js.png?fit=749%2C662&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/10\/found-2-cypress-configuration-files-named-cypress-config-ts-cypress-config-js.png?fit=749%2C662&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/10\/found-2-cypress-configuration-files-named-cypress-config-ts-cypress-config-js.png?fit=749%2C662&ssl=1&resize=700%2C400 2x"},"classes":[]},{"id":1503,"url":"https:\/\/codereviewvideos.com\/typescript-type-guard-example\/","url_meta":{"origin":1406,"position":5},"title":"TypeScript Type Guard Example","author":"Chris","date":"29 November 2023","format":false,"excerpt":"I was reviewing some TypeScript code this afternoon that had a type assertion (as) (also commonly called a 'cast') in there that could have been avoided by using a Type Guard. Type Guards are one of my favourite features of TypeScript. That makes me sound like a real nerd. But\u2026","rel":"","context":"In &quot;JavaScript &amp; TypeScript&quot;","block_context":{"text":"JavaScript &amp; TypeScript","link":"https:\/\/codereviewvideos.com\/category\/javascript-typescript-nodejs\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/11\/typescript-TS2339-property-does-not-exist-on-both-types.png?fit=721%2C338&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/11\/typescript-TS2339-property-does-not-exist-on-both-types.png?fit=721%2C338&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/11\/typescript-TS2339-property-does-not-exist-on-both-types.png?fit=721%2C338&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/codereviewvideos.com\/wp-content\/uploads\/2023\/11\/typescript-TS2339-property-does-not-exist-on-both-types.png?fit=721%2C338&ssl=1&resize=700%2C400 2x"},"classes":[]}],"jetpack_shortlink":"https:\/\/wp.me\/peo7Yh-mG","_links":{"self":[{"href":"https:\/\/codereviewvideos.com\/wp-json\/wp\/v2\/posts\/1406","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/codereviewvideos.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/codereviewvideos.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/codereviewvideos.com\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/codereviewvideos.com\/wp-json\/wp\/v2\/comments?post=1406"}],"version-history":[{"count":4,"href":"https:\/\/codereviewvideos.com\/wp-json\/wp\/v2\/posts\/1406\/revisions"}],"predecessor-version":[{"id":1438,"href":"https:\/\/codereviewvideos.com\/wp-json\/wp\/v2\/posts\/1406\/revisions\/1438"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/codereviewvideos.com\/wp-json\/wp\/v2\/media\/1409"}],"wp:attachment":[{"href":"https:\/\/codereviewvideos.com\/wp-json\/wp\/v2\/media?parent=1406"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/codereviewvideos.com\/wp-json\/wp\/v2\/categories?post=1406"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/codereviewvideos.com\/wp-json\/wp\/v2\/tags?post=1406"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}