<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: ReactChallenges</title>
    <description>The latest articles on DEV Community by ReactChallenges (@reactchallenges).</description>
    <link>https://dev.to/reactchallenges</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F854942%2Fe450946a-3098-4715-8d06-0892ab9ac221.png</url>
      <title>DEV Community: ReactChallenges</title>
      <link>https://dev.to/reactchallenges</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/reactchallenges"/>
    <language>en</language>
    <item>
      <title>🚀 New React Challenge: Undo / Redo</title>
      <dc:creator>ReactChallenges</dc:creator>
      <pubDate>Wed, 07 Oct 2026 09:04:45 +0000</pubDate>
      <link>https://dev.to/reactchallenges/new-react-challenge-undo-redo-40h0</link>
      <guid>https://dev.to/reactchallenges/new-react-challenge-undo-redo-40h0</guid>
      <description>&lt;p&gt;Most apps let users make changes but never let them take them back. This challenge is about building the mechanism that changes everything: a history you can rewind.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧩 Overview
&lt;/h2&gt;

&lt;p&gt;Build a notes editor whose add, edit, toggle, and delete actions are tracked in a &lt;code&gt;useReducer&lt;/code&gt; past/present/future history, so every change can be undone and redone with buttons or keyboard shortcuts.&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://www.reactchallenges.com/challenges/undo-redo" rel="noopener noreferrer"&gt;https://www.reactchallenges.com/challenges/undo-redo&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  ✅ Requirements
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The list starts with the notes "Buy groceries" and "Walk the dog".&lt;/li&gt;
&lt;li&gt;Each note is editable through an input.&lt;/li&gt;
&lt;li&gt;Each note has a done toggle and a delete button.&lt;/li&gt;
&lt;li&gt;Undo and redo are disabled on first render.&lt;/li&gt;
&lt;li&gt;Adding a note appends it to the list and clears the new-note field.&lt;/li&gt;
&lt;li&gt;A change enables undo; undoing restores the previous list, disables undo when there is nothing left to undo, and enables redo.&lt;/li&gt;
&lt;li&gt;Redo reapplies an undone change and disables itself once there is nothing left to redo.&lt;/li&gt;
&lt;li&gt;Adding, editing, toggling, and deleting a note can each be undone.&lt;/li&gt;
&lt;li&gt;An undone change can be redone.&lt;/li&gt;
&lt;li&gt;Consecutive edits to the same note collapse into a single undo step.&lt;/li&gt;
&lt;li&gt;An edit that does not change the text is ignored and adds no history.&lt;/li&gt;
&lt;li&gt;Adding an empty or whitespace-only note is ignored and adds no history.&lt;/li&gt;
&lt;li&gt;Undo is triggered by Cmd/Ctrl+Z.&lt;/li&gt;
&lt;li&gt;Redo is triggered by Shift+Ctrl+Z.&lt;/li&gt;
&lt;li&gt;Pressing undo with no history or redo with nothing to redo leaves the list unchanged.&lt;/li&gt;
&lt;li&gt;The status line reports how many undo and redo steps are available.&lt;/li&gt;
&lt;li&gt;New notes always get unique identifiers, even after undoing and adding again.&lt;/li&gt;
&lt;li&gt;Making a new change after undoing clears the redo stack.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  💡 Notes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The history shape most people reach for is &lt;code&gt;{ past, present, future }&lt;/code&gt;: &lt;code&gt;present&lt;/code&gt; is what renders, while &lt;code&gt;past&lt;/code&gt; and &lt;code&gt;future&lt;/code&gt; are stacks of snapshots.&lt;/li&gt;
&lt;li&gt;Return the same state object for a no-op (a blank note, an edit that doesn't change the text, undo/redo with an empty stack) so React bails out and history stays clean.&lt;/li&gt;
&lt;li&gt;Keep the id counter outside the history — rewinding it on undo would let two different notes share an id.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🧪 Tests
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;renders the initial notes&lt;/li&gt;
&lt;li&gt;disables undo and redo on load&lt;/li&gt;
&lt;li&gt;adds a note and clears the input&lt;/li&gt;
&lt;li&gt;enables undo after a change and disables it again after undoing&lt;/li&gt;
&lt;li&gt;redoes an undone change&lt;/li&gt;
&lt;li&gt;undoes a deletion and restores the note&lt;/li&gt;
&lt;li&gt;undoes a toggle and restores the previous state&lt;/li&gt;
&lt;li&gt;undoes an edit and restores the previous text&lt;/li&gt;
&lt;li&gt;collapses continuous edits to one note into a single undo step&lt;/li&gt;
&lt;li&gt;ignores an edit that does not change the text&lt;/li&gt;
&lt;li&gt;does not push history when adding an empty note&lt;/li&gt;
&lt;li&gt;does not push history when adding a whitespace-only note&lt;/li&gt;
&lt;li&gt;undoes with Ctrl+Z&lt;/li&gt;
&lt;li&gt;undoes with Cmd+Z&lt;/li&gt;
&lt;li&gt;redoes with Shift+Ctrl+Z&lt;/li&gt;
&lt;li&gt;does nothing when undo is pressed with no history&lt;/li&gt;
&lt;li&gt;does nothing when redo is pressed with no future&lt;/li&gt;
&lt;li&gt;reports the available undo and redo steps&lt;/li&gt;
&lt;li&gt;keeps note identifiers unique after undo and redo&lt;/li&gt;
&lt;li&gt;clears the redo stack when a new change is made&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;Work through it and you'll come away knowing how to model reversible state with a reducer — a skill that shows up everywhere from text editors to form builders to drag-and-drop canvases.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.reactchallenges.com/challenges/undo-redo" rel="noopener noreferrer"&gt;🔥 Start the Challenge Now&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>frontend</category>
      <category>frontendchallenge</category>
    </item>
    <item>
      <title>🚀 𝗡𝗲𝘄 𝗥𝗲𝗮𝗰𝘁 𝗖𝗵𝗮𝗹𝗹𝗲𝗻𝗴𝗲: Virtualized List</title>
      <dc:creator>ReactChallenges</dc:creator>
      <pubDate>Wed, 30 Sep 2026 11:46:25 +0000</pubDate>
      <link>https://dev.to/reactchallenges/-virtualized-list-4593</link>
      <guid>https://dev.to/reactchallenges/-virtualized-list-4593</guid>
      <description>&lt;p&gt;Ever hit a wall when a list grows to thousands of rows and React starts to choke? Mounting 10,000 DOM nodes at once is the problem — rendering only what fits on screen is the fix.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧩 Overview
&lt;/h2&gt;

&lt;p&gt;Build a virtualized list of 10,000 contacts that mounts only the rows visible in the scroll viewport (plus a small overscan), using fixed row heights and windowing math.&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://www.reactchallenges.com/challenges/virtualized-list" rel="noopener noreferrer"&gt;https://www.reactchallenges.com/challenges/virtualized-list&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  ✅ Requirements
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Render a virtualized directory of 10,000 contacts.&lt;/li&gt;
&lt;li&gt;Mount only a small window of rows — far fewer than the 10,000 in the dataset.&lt;/li&gt;
&lt;li&gt;Scroll through the entire dataset, not just the mounted rows.&lt;/li&gt;
&lt;li&gt;Size the scrollable area to the full dataset so the scrollbar spans the whole list.&lt;/li&gt;
&lt;li&gt;Unmount rows that leave the viewport and mount the ones that enter it.&lt;/li&gt;
&lt;li&gt;Keep a few overscan rows above and below the visible window.&lt;/li&gt;
&lt;li&gt;Show the first and last mounted rows in a stats line: &lt;code&gt;Showing X–Y of 10000&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Display each contact's name and email in its row.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  💡 Notes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Put all the windowing logic in &lt;code&gt;App.tsx&lt;/code&gt;: track &lt;code&gt;scrollTop&lt;/code&gt;, measure the viewport's &lt;code&gt;clientHeight&lt;/code&gt;, and compute the range of rows to mount.&lt;/li&gt;
&lt;li&gt;Measure the viewport height in a layout effect — it's the moment the layout is ready.&lt;/li&gt;
&lt;li&gt;Clamp the range so overscan never renders rows before the first or after the last contact.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🧪 Tests
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Renders the app title&lt;/li&gt;
&lt;li&gt;Only mounts a small window of rows, not the whole dataset&lt;/li&gt;
&lt;li&gt;Renders the first contacts on load&lt;/li&gt;
&lt;li&gt;Sizes the scrollable area to the full dataset&lt;/li&gt;
&lt;li&gt;Shows the first and last rendered rows in the stats&lt;/li&gt;
&lt;li&gt;Renders more rows than fit on screen (overscan)&lt;/li&gt;
&lt;li&gt;Shows the name and email for each mounted row&lt;/li&gt;
&lt;li&gt;Moves the window down when scrolling&lt;/li&gt;
&lt;li&gt;Restores the first rows when scrolling back to the top&lt;/li&gt;
&lt;li&gt;Renders the last contact when scrolled to the bottom&lt;/li&gt;
&lt;li&gt;Mounts overscan rows above the visible window when scrolled&lt;/li&gt;
&lt;li&gt;Never renders rows above the first one&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;This challenge is a hands-on way to understand virtualization from scratch — the exact pattern behind every serious long-list library. Practice windowing math, &lt;code&gt;useLayoutEffect&lt;/code&gt;, and derived rendering, and your lists will stop freezing for good.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.reactchallenges.com/challenges/virtualized-list" rel="noopener noreferrer"&gt;🔥 Start the Challenge Now&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>frontend</category>
      <category>frontendchallenge</category>
    </item>
    <item>
      <title>🚀 New React Challenge: OTP Input</title>
      <dc:creator>ReactChallenges</dc:creator>
      <pubDate>Wed, 23 Sep 2026 12:00:08 +0000</pubDate>
      <link>https://dev.to/reactchallenges/new-react-challenge-otp-input-1ld9</link>
      <guid>https://dev.to/reactchallenges/new-react-challenge-otp-input-1ld9</guid>
      <description>&lt;p&gt;One-time-password inputs look simple until you try to build one. Auto-advancing focus, paste handling, and keyboard navigation all have to work together — and that's exactly what this challenge asks you to wire up.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧩 Overview
&lt;/h2&gt;

&lt;p&gt;Build a six-field OTP input that moves focus as you type, accepts a pasted code, and validates it against a demo code.&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://www.reactchallenges.com/challenges/otp-input" rel="noopener noreferrer"&gt;https://www.reactchallenges.com/challenges/otp-input&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  ✅ Requirements
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Six single-character inputs are rendered, one per digit.&lt;/li&gt;
&lt;li&gt;The first input is focused on mount.&lt;/li&gt;
&lt;li&gt;Typing a digit fills the focused input and moves focus to the next input.&lt;/li&gt;
&lt;li&gt;Non-numeric characters are ignored.&lt;/li&gt;
&lt;li&gt;Backspace clears the current digit and stays in place.&lt;/li&gt;
&lt;li&gt;Backspace on an already-empty input clears the previous digit and moves focus to it.&lt;/li&gt;
&lt;li&gt;ArrowLeft and ArrowRight move focus between inputs.&lt;/li&gt;
&lt;li&gt;Pasting a code fills the inputs with the pasted digits; digits beyond six are ignored.&lt;/li&gt;
&lt;li&gt;The status text reads "Waiting for code…" while the code is incomplete.&lt;/li&gt;
&lt;li&gt;When all six digits are filled and match the demo code, the status reads "Code verified".&lt;/li&gt;
&lt;li&gt;When all six digits are filled but do not match, the status reads "Invalid code. Try again."&lt;/li&gt;
&lt;li&gt;The reset button clears all inputs, refocuses the first input, and resets the status.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  💡 Notes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The six inputs are controlled: whatever logic you run in the change handler decides what actually sticks in state, so invalid characters never persist.&lt;/li&gt;
&lt;li&gt;You need to move focus between inputs imperatively — plan how to keep a reference to each field.&lt;/li&gt;
&lt;li&gt;A single interaction can deliver more than one digit at once (pasting a full code), not just one keypress.&lt;/li&gt;
&lt;li&gt;Call &lt;code&gt;preventDefault()&lt;/code&gt; on the keyboard and paste handlers so the browser doesn't also move the caret or insert text on its own.&lt;/li&gt;
&lt;li&gt;Prefer deriving the status from the current values instead of storing it as separate state that can drift out of sync.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🧪 Tests
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;renders six inputs&lt;/li&gt;
&lt;li&gt;focuses the first input on mount&lt;/li&gt;
&lt;li&gt;renders the demo code&lt;/li&gt;
&lt;li&gt;types a digit and moves focus to the next input&lt;/li&gt;
&lt;li&gt;ignores non-numeric characters&lt;/li&gt;
&lt;li&gt;backspace clears the current digit and stays in place&lt;/li&gt;
&lt;li&gt;backspace on an empty input clears the previous digit&lt;/li&gt;
&lt;li&gt;arrow keys move focus between inputs&lt;/li&gt;
&lt;li&gt;pastes the demo code and verifies it&lt;/li&gt;
&lt;li&gt;shows an error for a wrong code&lt;/li&gt;
&lt;li&gt;truncates extra digits when pasting more than six&lt;/li&gt;
&lt;li&gt;reset clears the inputs and refocuses the first&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;Mastering imperative focus management and derived state in a tiny, familiar UI. That's the skill this challenge leaves you with — useful every time you build auth, 2FA, or payment flows.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.reactchallenges.com/challenges/otp-input" rel="noopener noreferrer"&gt;🔥 Start the Challenge Now&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>typescript</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Context API vs Redux</title>
      <dc:creator>ReactChallenges</dc:creator>
      <pubDate>Sun, 20 Sep 2026 11:36:50 +0000</pubDate>
      <link>https://dev.to/reactchallenges/context-api-vs-redux-3o5e</link>
      <guid>https://dev.to/reactchallenges/context-api-vs-redux-3o5e</guid>
      <description>&lt;p&gt;The question is usually framed as "which one is better", but that's the wrong question. Context and Redux do different jobs. The important part is understanding how each one updates its consumers.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;👉 Try it in practice: &lt;a href="https://www.reactchallenges.com/challenges/shopping-cart" rel="noopener noreferrer"&gt;Shopping Cart with Context&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What Context actually does
&lt;/h2&gt;

&lt;p&gt;Context lets a component read and subscribe to a value without threading it down through props. The context object itself does not hold data; it only describes what can be provided and read. To make the value change, you pair the provider with &lt;code&gt;useState&lt;/code&gt; or &lt;code&gt;useReducer&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ThemeContext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;light&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setTheme&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;light&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ThemeContext&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Page&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;ThemeContext&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key detail, from the React docs: when the value you pass to a provider changes, React re-renders every component that reads that context. It compares the old and new values with &lt;code&gt;Object.is&lt;/code&gt;. There are no selectors, so you can't subscribe to just one field of the value.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Redux adds
&lt;/h2&gt;

&lt;p&gt;Redux is a centralized store with a single flow: action, reducer, store. Around that flow you get middleware, Redux DevTools, and an action history, so you can answer "when did this slice change and where did the data come from?".&lt;/p&gt;

&lt;p&gt;Its real advantage over Context is &lt;code&gt;useSelector&lt;/code&gt;. A component subscribes to the result it selects, not to the whole store:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useSelector&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cart&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;theme&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useSelector&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Change &lt;code&gt;cart&lt;/code&gt; and the component reading &lt;code&gt;theme&lt;/code&gt; does not re-render. With Context, it would.&lt;/p&gt;

&lt;h2&gt;
  
  
  The re-render difference
&lt;/h2&gt;

&lt;p&gt;A Context subscription is to the context value as a whole, not to individual fields. Put &lt;code&gt;{ user, cart, theme }&lt;/code&gt; in a single context and changing &lt;code&gt;cart&lt;/code&gt; re-renders the component that only reads &lt;code&gt;theme&lt;/code&gt; too. You can fix this by splitting into multiple contexts and memoizing values, but that's work you do by hand. Redux gives you granular subscriptions through selectors.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to use each
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Context&lt;/strong&gt; for simple shared values with few consumers: theme, locale, current user, and state scoped to one feature. Zero dependencies.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Redux&lt;/strong&gt; when shared client state gets large, is used in many places, or has update logic that's getting complex. It also helps when you need to inspect how state changes over time with Redux DevTools.&lt;/p&gt;

&lt;p&gt;Data fetched from an API is server state and belongs in SWR or React Query, not in either of these.&lt;/p&gt;

&lt;h2&gt;
  
  
  A real example: the shopping cart
&lt;/h2&gt;

&lt;p&gt;A cart with a few items, a header badge, and a checkout button is fine in Context.&lt;/p&gt;

&lt;p&gt;Watch what happens as it grows: a coupon field, a quantity stepper, a "save for later" list. Now items, coupon, and saved share one context. Updating items re-renders the coupon and saved consumers too. Put the coupon draft in that same context and every keystroke re-renders the header badge.&lt;/p&gt;

&lt;p&gt;That's where selectors earn their keep: components can subscribe to different slices of state independently, and a component re-renders only when the piece it reads changes. Redux DevTools and action history are the bonus on top.&lt;/p&gt;

&lt;p&gt;Start with Context. Reach for a store when the state and its consumers get complex enough to justify it, not before.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;👉 Build both and compare: &lt;a href="https://www.reactchallenges.com/challenges/shopping-cart-with-redux" rel="noopener noreferrer"&gt;Shopping Cart with Redux&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>frontend</category>
      <category>redux</category>
    </item>
    <item>
      <title>🚀 New React Challenge: Command Palette</title>
      <dc:creator>ReactChallenges</dc:creator>
      <pubDate>Wed, 16 Sep 2026 10:08:15 +0000</pubDate>
      <link>https://dev.to/reactchallenges/new-react-challenge-command-palette-24jn</link>
      <guid>https://dev.to/reactchallenges/new-react-challenge-command-palette-24jn</guid>
      <description>&lt;p&gt;Search bars are fine until someone hits Cmd/Ctrl+K. A command palette replaces hunting through menus with a keyboard-first layer that filters as you type — and building one forces you to combine global keyboard handling, focus management and correct ARIA semantics in a single component.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧩 Overview
&lt;/h2&gt;

&lt;p&gt;Build a keyboard-driven command palette (Cmd/Ctrl+K) with fuzzy filtering, arrow-key navigation, a focus trap and proper combobox/listbox semantics.&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://www.reactchallenges.com/challenges/command-palette" rel="noopener noreferrer"&gt;https://www.reactchallenges.com/challenges/command-palette&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  ✅ Requirements
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The palette is hidden on first render.&lt;/li&gt;
&lt;li&gt;Clicking the trigger opens the palette.&lt;/li&gt;
&lt;li&gt;Pressing Cmd/Ctrl+K opens the palette, and pressing it again closes it.&lt;/li&gt;
&lt;li&gt;Pressing Escape closes the palette.&lt;/li&gt;
&lt;li&gt;Clicking the backdrop closes the palette, while clicking inside the panel keeps it open.&lt;/li&gt;
&lt;li&gt;When the palette opens, the search input receives focus and is empty.&lt;/li&gt;
&lt;li&gt;The palette lists every command.&lt;/li&gt;
&lt;li&gt;Typing filters the commands by fuzzy match: every character of the query must appear in the label in order, ignoring case.&lt;/li&gt;
&lt;li&gt;When nothing matches, show &lt;code&gt;No results for "&amp;lt;query&amp;gt;"&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Clearing the query restores the full list.&lt;/li&gt;
&lt;li&gt;The first command is highlighted when the palette opens and whenever the query changes.&lt;/li&gt;
&lt;li&gt;ArrowDown moves the highlight to the next command, wrapping from the last one to the first.&lt;/li&gt;
&lt;li&gt;ArrowUp moves the highlight to the previous command, wrapping from the first one to the last.&lt;/li&gt;
&lt;li&gt;Enter executes the highlighted command and closes the palette.&lt;/li&gt;
&lt;li&gt;Clicking a command executes it and closes the palette.&lt;/li&gt;
&lt;li&gt;Executing a command sets the &lt;code&gt;Last action&lt;/code&gt; text to that command's label.&lt;/li&gt;
&lt;li&gt;While the palette is open, focus stays inside it when pressing Tab.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  💡 Notes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Open and close from a single &lt;code&gt;window&lt;/code&gt; &lt;code&gt;keydown&lt;/code&gt; listener for Cmd/Ctrl+K and Escape, and call &lt;code&gt;preventDefault()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Filter by subsequence, not &lt;code&gt;includes&lt;/code&gt; ("gch" matches "Go to Challenges"), and reset &lt;code&gt;activeIndex&lt;/code&gt; when the query changes.&lt;/li&gt;
&lt;li&gt;Focus the input on open and keep focus trapped inside the panel by listening for &lt;code&gt;focusin&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🧪 Tests
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;keeps the palette hidden on first render&lt;/li&gt;
&lt;li&gt;opens the palette when the trigger is clicked&lt;/li&gt;
&lt;li&gt;opens the palette with Cmd/Ctrl+K&lt;/li&gt;
&lt;li&gt;focuses the search input when opened&lt;/li&gt;
&lt;li&gt;closes the palette when the shortcut is pressed again&lt;/li&gt;
&lt;li&gt;closes the palette on Escape&lt;/li&gt;
&lt;li&gt;closes the palette when the backdrop is clicked&lt;/li&gt;
&lt;li&gt;keeps the palette open when clicking inside the panel&lt;/li&gt;
&lt;li&gt;renders every command&lt;/li&gt;
&lt;li&gt;filters commands as the user types&lt;/li&gt;
&lt;li&gt;matches non-contiguous characters&lt;/li&gt;
&lt;li&gt;is case-insensitive&lt;/li&gt;
&lt;li&gt;shows a no-results message when nothing matches&lt;/li&gt;
&lt;li&gt;restores the full list when the query is cleared&lt;/li&gt;
&lt;li&gt;clears the query when the palette is reopened&lt;/li&gt;
&lt;li&gt;highlights the first command by default&lt;/li&gt;
&lt;li&gt;moves the highlight down with ArrowDown&lt;/li&gt;
&lt;li&gt;wraps from the first to the last with ArrowUp&lt;/li&gt;
&lt;li&gt;wraps from the last to the first with ArrowDown&lt;/li&gt;
&lt;li&gt;resets the highlight when the query changes&lt;/li&gt;
&lt;li&gt;executes the highlighted command with Enter&lt;/li&gt;
&lt;li&gt;executes a command when clicked&lt;/li&gt;
&lt;li&gt;traps focus inside the palette on Tab&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;If you want to practice keyboard-driven UI the way real apps do it, this challenge gives you the full loop: open, filter, navigate, execute and trap focus — with 23 tests to keep you honest.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.reactchallenges.com/challenges/command-palette" rel="noopener noreferrer"&gt;🔥 Start the Challenge Now&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>frontend</category>
      <category>frontendchallenge</category>
    </item>
    <item>
      <title>5 common TypeScript interview questions</title>
      <dc:creator>ReactChallenges</dc:creator>
      <pubDate>Thu, 10 Sep 2026 09:40:33 +0000</pubDate>
      <link>https://dev.to/reactchallenges/5-common-typescript-interview-questions-10jb</link>
      <guid>https://dev.to/reactchallenges/5-common-typescript-interview-questions-10jb</guid>
      <description>&lt;p&gt;These five questions show up in almost every TypeScript interview. They're not tricky syntax puzzles. They test whether you understand the type system well enough to use it on purpose instead of just making the compiler happy.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;any&lt;/code&gt; vs &lt;code&gt;unknown&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;any&lt;/code&gt; turns type checking off. Once a value is &lt;code&gt;any&lt;/code&gt;, TypeScript stops protecting you and mistakes slip through until runtime. &lt;code&gt;unknown&lt;/code&gt; is the safe counterpart: it can hold anything, but you must narrow it before using it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hello&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toUpperCase&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// ✅ no error&lt;/span&gt;
&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;thisDoesNotExist&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// ✅ no error either 💀&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;u&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hello&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toUpperCase&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// ❌ 'u' is of type 'unknown'&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;u&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toUpperCase&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// ✅ narrowed to string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Reach for &lt;code&gt;unknown&lt;/code&gt; when the type is genuinely unknown, like API responses, &lt;code&gt;JSON.parse&lt;/code&gt;, or &lt;code&gt;catch&lt;/code&gt; variables, and never reach for &lt;code&gt;any&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;interface&lt;/code&gt; vs &lt;code&gt;type&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Both describe object shapes and are mostly interchangeable. The real differences are what each one can express.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;interface&lt;/code&gt; supports &lt;strong&gt;declaration merging&lt;/strong&gt;; &lt;code&gt;type&lt;/code&gt; doesn't.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;type&lt;/code&gt; can express unions, intersections, tuples, and primitives; &lt;code&gt;interface&lt;/code&gt; only describes object-like shapes.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;interface&lt;/code&gt; extends with &lt;code&gt;extends&lt;/code&gt;; &lt;code&gt;type&lt;/code&gt; composes with &lt;code&gt;&amp;amp;&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;// merged: { name: string; age: number }&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// only possible with type&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Declaration merging cuts both ways: it lets libraries augment existing types (like extending &lt;code&gt;Window&lt;/code&gt;), but it can also merge a typo into a valid type. A common convention is &lt;code&gt;interface&lt;/code&gt; for object APIs and &lt;code&gt;type&lt;/code&gt; for unions and computed types.&lt;/p&gt;

&lt;h2&gt;
  
  
  Generics
&lt;/h2&gt;

&lt;p&gt;Generics let you write code that works with many types while preserving the relationship between input and output. Without them you'd duplicate the function per type or fall back to &lt;code&gt;any&lt;/code&gt; and lose the return type.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[]):&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt; &lt;span class="c1"&gt;// number | undefined&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;b&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt; &lt;span class="c1"&gt;// string | undefined&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can constrain them when you need to rely on some structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getProperty&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;K&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;K&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Alice&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nf"&gt;getProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// ✅ string&lt;/span&gt;
&lt;span class="nf"&gt;getProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;age&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// ❌ "age" is not assignable to keyof typeof user&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The definition is easy to recite. The interview signal is being able to show a case where a generic removed duplication or a lost type.&lt;/p&gt;

&lt;h2&gt;
  
  
  Utility types
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Partial&lt;/code&gt;, &lt;code&gt;Pick&lt;/code&gt;, &lt;code&gt;Omit&lt;/code&gt;, and &lt;code&gt;Record&lt;/code&gt; are built-in generics. They're not magic, but &lt;strong&gt;mapped types&lt;/strong&gt; that transform an existing type into a new one.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;PartialUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Partial&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// every property optional&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;UserPreview&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Pick&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// only id and name&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;UserWithoutEmail&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Omit&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// everything except email&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;UsersById&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// { [key: string]: User }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Under the hood, &lt;code&gt;Partial&lt;/code&gt; is roughly this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nb"&gt;Partial&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]?:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Knowing the mapping is what separates "I know they exist" from "I know how to build my own".&lt;/p&gt;

&lt;h2&gt;
  
  
  Type guards
&lt;/h2&gt;

&lt;p&gt;A type guard is an expression that gives TypeScript information it can use to &lt;strong&gt;narrow&lt;/strong&gt; a broader type into a more specific one within a block. Common narrowing checks include &lt;code&gt;typeof&lt;/code&gt;, &lt;code&gt;instanceof&lt;/code&gt;, &lt;code&gt;in&lt;/code&gt;, and equality checks.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toUpperCase&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// string&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toFixed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// number&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you want to reuse a check across your code, wrap it in a named type guard using a &lt;strong&gt;type predicate&lt;/strong&gt; (&lt;code&gt;x is T&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Cat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;meow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Dog&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;bark&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;isCat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;animal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Cat&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;animal&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;Cat&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;meow&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;animal&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now TypeScript can narrow the type when you call the guard:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;speak&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;animal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Cat&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;isCat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;animal&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;animal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;meow&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Cat&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;animal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bark&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Dog&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;animal is Cat&lt;/code&gt; return type is a contract: TypeScript trusts it and narrows &lt;code&gt;animal&lt;/code&gt; to &lt;code&gt;Cat&lt;/code&gt; when the function returns &lt;code&gt;true&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That means the logic inside the guard is your responsibility. If the predicate is wrong, TypeScript won't catch the resulting bug.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>javascript</category>
      <category>react</category>
      <category>programming</category>
    </item>
    <item>
      <title>🚀 New React Challenge: Infinite Scroll</title>
      <dc:creator>ReactChallenges</dc:creator>
      <pubDate>Wed, 09 Sep 2026 09:53:24 +0000</pubDate>
      <link>https://dev.to/reactchallenges/new-react-challenge-infinite-scroll-1mi2</link>
      <guid>https://dev.to/reactchallenges/new-react-challenge-infinite-scroll-1mi2</guid>
      <description>&lt;p&gt;"Load more" buttons are the easy way out. Real feeds — Twitter, Instagram, your chat app — load the next page the moment you scroll near the bottom. That magic is the &lt;strong&gt;Intersection Observer API&lt;/strong&gt;, and it's much cleaner than the old scroll-listener + throttle dance.&lt;/p&gt;

&lt;p&gt;This challenge gets you building an infinite scroll list of &lt;strong&gt;Rick &amp;amp; Morty characters&lt;/strong&gt; with React 19's Suspense-driven &lt;code&gt;use()&lt;/code&gt; fetching already in place. Your job: make the next page fetch itself.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧩 Overview
&lt;/h2&gt;

&lt;p&gt;Build an infinite scroll list of Rick and Morty characters using the &lt;strong&gt;Intersection Observer API&lt;/strong&gt; — the next page is fetched automatically when a sentinel element enters the viewport, building on an existing &lt;code&gt;use()&lt;/code&gt; + Suspense data-fetching setup.&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://www.reactchallenges.com/challenges/infinite-scroll" rel="noopener noreferrer"&gt;https://www.reactchallenges.com/challenges/infinite-scroll&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  ✅ Requirements
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Keep the starter's &lt;code&gt;use()&lt;/code&gt; + Suspense first-page fetch as the starting point&lt;/li&gt;
&lt;li&gt;Follow the API pagination and read the next page URL from &lt;code&gt;data.info.next&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Load the next page automatically when the user scrolls to the bottom — no button&lt;/li&gt;
&lt;li&gt;Trigger the load from a sentinel element observed by the Intersection Observer&lt;/li&gt;
&lt;li&gt;Append new characters to the existing list instead of replacing them&lt;/li&gt;
&lt;li&gt;Show a loading indicator while the next page is being fetched&lt;/li&gt;
&lt;li&gt;Hide the loading indicator once the page finishes loading&lt;/li&gt;
&lt;li&gt;Show an end-of-list message when there are no more pages&lt;/li&gt;
&lt;li&gt;Stop fetching once the end is reached — no requests when &lt;code&gt;info.next&lt;/code&gt; is &lt;code&gt;null&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Disconnect the observer when the component unmounts&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  💡 Notes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;App&lt;/code&gt; is fully wired: title, layout, and the Suspense fallback are done — all your work happens inside &lt;code&gt;Characters()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The components file is read-only, and the API follows the classic &lt;code&gt;{ info: { next, prev }, results: [...] }&lt;/code&gt; Rick &amp;amp; Morty response shape.&lt;/li&gt;
&lt;li&gt;Watch out: a couple of tests pass with the starter code simply because nothing fetches yet — they only start validating real behavior once your observer is in place.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🧪 Tests
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;renders the app title&lt;/li&gt;
&lt;li&gt;shows skeleton while loading&lt;/li&gt;
&lt;li&gt;renders first-page characters after loading&lt;/li&gt;
&lt;li&gt;observes the sentinel element&lt;/li&gt;
&lt;li&gt;loads the next page when the sentinel enters the viewport&lt;/li&gt;
&lt;li&gt;appends characters instead of replacing them&lt;/li&gt;
&lt;li&gt;loads the third page on repeated intersections&lt;/li&gt;
&lt;li&gt;shows a loading indicator while fetching the next page&lt;/li&gt;
&lt;li&gt;hides the loading indicator once the next page loads&lt;/li&gt;
&lt;li&gt;shows end of list when there are no more pages&lt;/li&gt;
&lt;li&gt;does not fetch again once the end is reached&lt;/li&gt;
&lt;li&gt;disconnects the observer on unmount&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;Infinite scroll is one of those tasks that shows up again and again in frontend interviews and real products.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.reactchallenges.com/challenges/infinite-scroll" rel="noopener noreferrer"&gt;🔥 Start the Challenge Now&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>frontend</category>
      <category>frontendchallenge</category>
    </item>
    <item>
      <title>🚀 New React Challenge: Roll dices</title>
      <dc:creator>ReactChallenges</dc:creator>
      <pubDate>Wed, 02 Sep 2026 08:29:15 +0000</pubDate>
      <link>https://dev.to/reactchallenges/new-react-challenge-roll-dices-4fad</link>
      <guid>https://dev.to/reactchallenges/new-react-challenge-roll-dices-4fad</guid>
      <description>&lt;p&gt;Most of us write &lt;code&gt;Math.floor(Math.random() * n)&lt;/code&gt; on autopilot and only realize later that the boundaries are wrong — inclusive when you wanted exclusive, or off by one. This challenge replaces that guesswork with practice: build a dice roller and three random number generators where getting the range right is the whole point.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧩 Overview
&lt;/h2&gt;

&lt;p&gt;Build a dice roller app plus three random number generators, practicing how to convert &lt;code&gt;Math.random()&lt;/code&gt; into random integer values across different ranges.&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://www.reactchallenges.com/challenges/roll-dices" rel="noopener noreferrer"&gt;https://www.reactchallenges.com/challenges/roll-dices&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  ✅ Requirements
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A form with an input that defaults to &lt;code&gt;3&lt;/code&gt; and only accepts values between &lt;code&gt;1&lt;/code&gt; and &lt;code&gt;6&lt;/code&gt;, submitted with a &lt;strong&gt;Roll&lt;/strong&gt; button.&lt;/li&gt;
&lt;li&gt;On submit, roll as many dice as the input value — rendering one &lt;code&gt;Dice&lt;/code&gt; component per dice, each showing a random value between &lt;code&gt;1&lt;/code&gt; and &lt;code&gt;6&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Add three random number generators, each with its own &lt;strong&gt;Roll&lt;/strong&gt; button and a result display, producing random integers:

&lt;ul&gt;
&lt;li&gt;Between &lt;code&gt;-10&lt;/code&gt; and &lt;code&gt;10&lt;/code&gt;, both included.&lt;/li&gt;
&lt;li&gt;Between &lt;code&gt;7&lt;/code&gt; and &lt;code&gt;14&lt;/code&gt;, both &lt;strong&gt;not&lt;/strong&gt; included.&lt;/li&gt;
&lt;li&gt;Between &lt;code&gt;0&lt;/code&gt; and &lt;code&gt;255&lt;/code&gt;, both included.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  💡 Notes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;code&gt;Dice.tsx&lt;/code&gt; component is provided and read-only, so you can focus on state and logic instead of markup.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🧪 Tests
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Default input value is 3&lt;/li&gt;
&lt;li&gt;Does not roll more than 6 dice&lt;/li&gt;
&lt;li&gt;Does not roll fewer than 1 dice&lt;/li&gt;
&lt;li&gt;Clicking roll renders a number of dice equal to the input value&lt;/li&gt;
&lt;li&gt;Random values map to valid dice faces&lt;/li&gt;
&lt;li&gt;First random generator returns values between -10 and 10, both included&lt;/li&gt;
&lt;li&gt;Second random generator returns values between 8 and 13, both not included&lt;/li&gt;
&lt;li&gt;Third random generator returns values between 0 and 255, both included&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;If you have ever doubted whether your random range formula is right, this is a quick, test-driven way to lock it in. You'll finish confident mapping &lt;code&gt;Math.random()&lt;/code&gt; to any range — and rendering a list of components from state while you are at it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.reactchallenges.com/challenges/roll-dices" rel="noopener noreferrer"&gt;🔥 Start the Challenge Now&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>frontend</category>
      <category>frontendchallenge</category>
    </item>
    <item>
      <title>🚀 New React Challenge: Calendar Events</title>
      <dc:creator>ReactChallenges</dc:creator>
      <pubDate>Wed, 26 Aug 2026 11:27:51 +0000</pubDate>
      <link>https://dev.to/reactchallenges/new-react-challenge-calendar-events-4k87</link>
      <guid>https://dev.to/reactchallenges/new-react-challenge-calendar-events-4k87</guid>
      <description>&lt;h2&gt;
  
  
  🧩 Overview
&lt;/h2&gt;

&lt;p&gt;Build a calendar that renders events on their days, supports selecting a day, and lets you add and delete events — practicing state management and data transformation keyed by absolute date strings.&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://www.reactchallenges.com/challenges/calendar-events" rel="noopener noreferrer"&gt;https://www.reactchallenges.com/challenges/calendar-events&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  ✅ Requirements
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Select a day by clicking it, highlighting the selected cell.&lt;/li&gt;
&lt;li&gt;Show the events of the selected day in a panel below the calendar, including a heading with the selected date.&lt;/li&gt;
&lt;li&gt;Add a new event via a text input and an "Add" button; empty or whitespace-only titles are ignored.&lt;/li&gt;
&lt;li&gt;Delete an event from the selected day via its delete button.&lt;/li&gt;
&lt;li&gt;Show a "no events" message for a selected day without events.&lt;/li&gt;
&lt;li&gt;Keep events intact when navigating between months — events are keyed by absolute &lt;code&gt;YYYY-MM-DD&lt;/code&gt; dates.&lt;/li&gt;
&lt;li&gt;Show an event dot on every day that has at least one event.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  💡 Notes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Components and the month-grid logic are already wired — your job is the events state: events, the selected day, filtering, and add/delete.&lt;/li&gt;
&lt;li&gt;Pass your events to &lt;code&gt;buildMonthDays(date, events)&lt;/code&gt; and the dots appear automatically.&lt;/li&gt;
&lt;li&gt;Filter events per day by comparing each event's date to the selected day; this keeps events stable across month navigation.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🧪 Tests
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Does not show dots on a day without events&lt;/li&gt;
&lt;li&gt;Selecting a day highlights it&lt;/li&gt;
&lt;li&gt;Shows the selected date in the panel heading&lt;/li&gt;
&lt;li&gt;Adds a new event via the Add button&lt;/li&gt;
&lt;li&gt;Adds a new event when pressing Enter&lt;/li&gt;
&lt;li&gt;Ignores empty titles when adding&lt;/li&gt;
&lt;li&gt;Shows a dot on the day of a newly added event&lt;/li&gt;
&lt;li&gt;Supports multiple events on the same day&lt;/li&gt;
&lt;li&gt;Shows only the events of the selected day&lt;/li&gt;
&lt;li&gt;Deletes an event from the selected day&lt;/li&gt;
&lt;li&gt;Keeps events when navigating between months&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;Whether you're prepping for interviews or sharpening your state skills, this is a compact, satisfying build — the calendar is already done, so you can focus entirely on managing events like a pro.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.reactchallenges.com/challenges/calendar-events" rel="noopener noreferrer"&gt;🔥 Start the Challenge Now&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>frontend</category>
      <category>frontendchallenge</category>
    </item>
    <item>
      <title>🚀 New React Challenge: Calendar</title>
      <dc:creator>ReactChallenges</dc:creator>
      <pubDate>Thu, 20 Aug 2026 17:00:37 +0000</pubDate>
      <link>https://dev.to/reactchallenges/new-react-challenge-calendar-3ak6</link>
      <guid>https://dev.to/reactchallenges/new-react-challenge-calendar-3ak6</guid>
      <description>&lt;p&gt;We all reach for a date library the moment a calendar shows up in a feature request. But underneath every grid is plain JavaScript — counting days, offsetting weekdays, and rolling years over. This challenge drops the library and puts you in charge.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧩 Overview
&lt;/h2&gt;

&lt;p&gt;The calendar components are already provided, so your job is the logic: render the correct days, highlight today, navigate between months, and handle leap years with plain JavaScript date math.&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://www.reactchallenges.com/challenges/calendar" rel="noopener noreferrer"&gt;https://www.reactchallenges.com/challenges/calendar&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  ✅ Requirements
&lt;/h2&gt;

&lt;p&gt;• Render the app title "Calendar" and the weekday header (Mon through Sun).&lt;br&gt;
• Show the current month and year in the header (e.g. August 2026).&lt;br&gt;
• Render the correct number of days for the selected month (28, 29, 30, or 31).&lt;br&gt;
• Place the 1st day of the month in the correct weekday column.&lt;br&gt;
• Fill empty cells with days from the previous and next month so the grid always completes full weeks, dimming those days visually.&lt;br&gt;
• Navigate to the previous and next month.&lt;br&gt;
• Highlight the current day (today) in the grid.&lt;br&gt;
• Change the year correctly when navigating past December or before January.&lt;br&gt;
• Handle leap years correctly (February has 29 days in a leap year, 28 otherwise).&lt;/p&gt;




&lt;h2&gt;
  
  
  💡 Notes
&lt;/h2&gt;

&lt;p&gt;• &lt;code&gt;new Date(year, month + 1, 0).getDate()&lt;/code&gt; returns the number of days in a month — leap years included.&lt;br&gt;
• The week starts on Monday, so the leading offset for the 1st day is &lt;code&gt;(getDay() + 6) % 7&lt;/code&gt;.&lt;br&gt;
• &lt;code&gt;new Date(year, month + offset, 1)&lt;/code&gt; rolls the year over automatically when navigating past December or January.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧪 Tests
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;renders the app title&lt;/li&gt;
&lt;li&gt;renders the seven weekday labels&lt;/li&gt;
&lt;li&gt;shows the current month and year in the header&lt;/li&gt;
&lt;li&gt;renders the correct number of days for the current month&lt;/li&gt;
&lt;li&gt;places the 1st day on the correct weekday&lt;/li&gt;
&lt;li&gt;fills the grid with days from the previous and next month&lt;/li&gt;
&lt;li&gt;navigates to the next month&lt;/li&gt;
&lt;li&gt;navigates to the previous month&lt;/li&gt;
&lt;li&gt;changes the year when navigating past December&lt;/li&gt;
&lt;li&gt;changes the year when navigating before January&lt;/li&gt;
&lt;li&gt;highlights today's date&lt;/li&gt;
&lt;li&gt;does not highlight any day when viewing another month&lt;/li&gt;
&lt;li&gt;renders 28 days for February in a non-leap year&lt;/li&gt;
&lt;li&gt;renders 29 days for February in a leap year&lt;/li&gt;
&lt;li&gt;renders 30 days for a 30-day month&lt;/li&gt;
&lt;li&gt;uses five weeks when the month fits in five&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;You'll walk away confident counting days, offsetting weekdays, and handling leap years without a single dependency. 16 tests will tell you exactly where your grid breaks.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.reactchallenges.com/challenges/calendar" rel="noopener noreferrer"&gt;🔥 Start the Challenge Now&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>frontend</category>
      <category>frontendchallenge</category>
    </item>
    <item>
      <title>🚀 New React Challenge: GitHub Contribution Heatmap</title>
      <dc:creator>ReactChallenges</dc:creator>
      <pubDate>Wed, 05 Aug 2026 08:24:32 +0000</pubDate>
      <link>https://dev.to/reactchallenges/new-react-challenge-github-contribution-heatmap-3im1</link>
      <guid>https://dev.to/reactchallenges/new-react-challenge-github-contribution-heatmap-3im1</guid>
      <description>&lt;p&gt;Fetching data in React without a library means juggling useEffect, abort controllers, isLoading booleans, error state, and cache invalidation — all by hand. SWR, TanStack Query, and RTK Query solve all of that out of the box. This challenge has the grid and components pre-built — your job is to wire up SWR and bring the GitHub-style heatmap to life.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧩 Overview
&lt;/h2&gt;

&lt;p&gt;Fetch contribution data for a GitHub-style heatmap using SWR. The grid and components are already built — you wire up data fetching with loading skeletons, error handling, and year navigation to make it work.&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://www.reactchallenges.com/challenges/github-contribution-heatmap" rel="noopener noreferrer"&gt;https://www.reactchallenges.com/challenges/github-contribution-heatmap&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  ✅ Requirements
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Fetch contribution data from &lt;code&gt;https://example-heatmap?year={year}&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Write a custom fetcher that checks &lt;code&gt;res.ok&lt;/code&gt;, parses the error body, and throws on failure — SWR won't know a request failed unless the fetcher throws&lt;/li&gt;
&lt;li&gt;Display a loading skeleton while data is being fetched&lt;/li&gt;
&lt;li&gt;Display an error skeleton with the server's error message when the request fails&lt;/li&gt;
&lt;li&gt;Display the heatmap grid with flattened contributions on success&lt;/li&gt;
&lt;li&gt;Allow switching between years (2023–2026) with interactive buttons&lt;/li&gt;
&lt;li&gt;Highlight the currently selected year button&lt;/li&gt;
&lt;li&gt;Calculate the offset so January 1st aligns with the correct weekday column&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  💡 Notes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;contributions&lt;/code&gt; is a 2D array (weeks × days) — flatten it with &lt;code&gt;.flat()&lt;/code&gt; before passing to &lt;code&gt;HeatmapGrid&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;The mock API has a random 300-500ms delay and fails ~20% of the time&lt;/li&gt;
&lt;li&gt;The custom fetcher pattern is universal: SWR, TanStack Query, and RTK Query all require you to throw on non-ok responses&lt;/li&gt;
&lt;li&gt;The data is from Linus Torvalds' real GitHub contributions — every cell reflects actual commits, merges, and pull requests&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🧪 Tests
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Renders the app title&lt;/li&gt;
&lt;li&gt;Shows skeleton while loading&lt;/li&gt;
&lt;li&gt;Displays heatmap grid with contributions when data loads&lt;/li&gt;
&lt;li&gt;Shows skeleton with error when request fails&lt;/li&gt;
&lt;li&gt;Highlights 2026 as the selected year button&lt;/li&gt;
&lt;li&gt;Fetches new data when switching to a different year&lt;/li&gt;
&lt;li&gt;Aligns January 1st to the correct weekday for each year&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;Whether you're new to SWR or already using TanStack Query, this challenge reinforces the fetch-then-render pattern that every production React app relies on. Plus, you get to see Linus Torvalds' actual commit history rendered as a heatmap — pretty cool.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.reactchallenges.com/challenges/github-contribution-heatmap" rel="noopener noreferrer"&gt;🔥 Start the Challenge Now&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>frontend</category>
      <category>frontendchallenge</category>
    </item>
    <item>
      <title>Typing Polymorphic React Components in TypeScript</title>
      <dc:creator>ReactChallenges</dc:creator>
      <pubDate>Wed, 29 Jul 2026 13:33:00 +0000</pubDate>
      <link>https://dev.to/reactchallenges/typing-polymorphic-react-components-in-typescript-cl6</link>
      <guid>https://dev.to/reactchallenges/typing-polymorphic-react-components-in-typescript-cl6</guid>
      <description>&lt;p&gt;I recently came across an interview question about advanced TypeScript patterns, specifically how to type a &lt;code&gt;Button&lt;/code&gt; component that can also render as a link. These are the kinds of concepts that are easy to forget, especially if you don't write as much code by hand anymore because AI handles a lot of it.&lt;/p&gt;

&lt;p&gt;That's why it's worth revisiting them from time to time. One of the best ways to check whether you truly understand a concept is to explain it to yourself and honestly ask whether someone else could understand that explanation. So here we are.&lt;/p&gt;

&lt;h2&gt;
  
  
  Everything optional
&lt;/h2&gt;

&lt;p&gt;Everything is optional, so TypeScript can't infer whether this component should behave as a button or a link. Since there is no relationship between the props, invalid combinations are allowed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;href&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;target&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;type&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;submit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;reset&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;disabled&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;href&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt; &lt;span class="na"&gt;disabled&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;;&lt;/span&gt; &lt;span class="c1"&gt;// ✅ No TypeScript error&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Union types
&lt;/h2&gt;

&lt;p&gt;TypeScript says:&lt;/p&gt;

&lt;p&gt;"I have a value whose type is &lt;code&gt;LinkProps | ButtonProps&lt;/code&gt;. I'll check whether it matches one of the union members."&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;LinkProps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;target&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ButtonProps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;submit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;reset&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;disabled&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;LinkProps&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;ButtonProps&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;href&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt; &lt;span class="na"&gt;disabled&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;;&lt;/span&gt; &lt;span class="c1"&gt;// ❌ Property 'disabled' does not exist on type 'LinkProps'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Discriminated unions
&lt;/h2&gt;

&lt;p&gt;Sometimes you don't want to infer the rendered element from the props. Instead, you want the user to choose it explicitly.&lt;/p&gt;

&lt;p&gt;TypeScript says:&lt;/p&gt;

&lt;p&gt;"I have a value whose type is &lt;code&gt;LinkProps | ButtonProps&lt;/code&gt;. I'll use the &lt;code&gt;as&lt;/code&gt; property to determine which one it is."&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;LinkProps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;as&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;href&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;target&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ButtonProps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;as&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;type&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;submit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;reset&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;disabled&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;LinkProps&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;ButtonProps&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt; &lt;span class="na"&gt;as&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;;&lt;/span&gt; &lt;span class="c1"&gt;// ❌ Property 'href' does not exist on type 'ButtonProps'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Generic polymorphic components
&lt;/h2&gt;

&lt;p&gt;In React 19+, the recommended utility type is &lt;code&gt;React.ComponentProps&amp;lt;T&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It gives you all the props supported by the element or component represented by &lt;code&gt;T&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ElementType&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ComponentProps&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Button&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ElementType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;rest&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Component&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;rest&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; In production code you'll often see &lt;code&gt;Omit&amp;lt;React.ComponentProps&amp;lt;T&amp;gt;, "as"&amp;gt;&lt;/code&gt; instead of &lt;code&gt;React.ComponentProps&amp;lt;T&amp;gt;&lt;/code&gt;. This removes any existing &lt;code&gt;as&lt;/code&gt; prop from the rendered component. Since HTML elements like &lt;code&gt;"button"&lt;/code&gt; and &lt;code&gt;"a"&lt;/code&gt; don't define an &lt;code&gt;as&lt;/code&gt; prop, the simplified version used here is sufficient.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now TypeScript automatically infers the correct props based on the value of &lt;code&gt;as&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt; &lt;span class="na"&gt;as&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"a"&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;// ✅&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt; &lt;span class="na"&gt;as&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt; &lt;span class="na"&gt;disabled&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;// ✅&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt; &lt;span class="na"&gt;as&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;// ❌&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt; &lt;span class="na"&gt;as&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"a"&lt;/span&gt; &lt;span class="na"&gt;disabled&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;// ❌&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; If you're using React 18 or earlier, use &lt;code&gt;React.ComponentPropsWithoutRef&amp;lt;T&amp;gt;&lt;/code&gt; instead. Before React 19, &lt;code&gt;ref&lt;/code&gt; wasn't treated as a normal prop for function components, so excluding it was usually the correct choice.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;code&gt;React.ComponentProps&amp;lt;T&amp;gt;&lt;/code&gt; is equivalent to saying:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Give me all the props that the element or component &lt;code&gt;T&lt;/code&gt; accepts."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Unlike union types, there's no need to manually define every possible combination (&lt;code&gt;LinkProps | ButtonProps | ...&lt;/code&gt;). The props are computed directly from the generic type &lt;code&gt;T&lt;/code&gt;, making the component scalable to any HTML element or custom React component.&lt;/p&gt;

</description>
      <category>react</category>
      <category>typescript</category>
      <category>javascript</category>
      <category>frontend</category>
    </item>
  </channel>
</rss>
