Skip to solution
mediumFrontend

Describe the benefits of using TypeScript with React.

469 views
01

Understand the problem

Question presented to candidate: "What does TypeScript actually buy you in a React codebase?"

What a strong answer should cover:

  • Props become a checked contract. A component's prop types are its API, and every call site is verified against it — wrong types, missing required props, and values outside a union are all compile errors.
  • Typos in prop names are caught, which JSX otherwise swallows silently: an unknown prop just does nothing.
  • State setters are typed, so setCount("many") fails rather than corrupting state at runtime.
  • Discriminated unions model impossible states away — a loading union means you cannot read data before checking the status.
  • Refactoring becomes mechanical. Rename a prop and every call site errors; that is the difference between a rename and an audit.
  • Editor support is the daily win — autocomplete for props, jump to definition, inline docs. Often more valuable in practice than the error catching.
  • Honest costs: build and check time, typing complexity for generic components, and any quietly reintroducing every problem.
  • The rule of thumb: type the boundaries — props, API responses, context values — and let inference handle the interior.

Clarifying questions expected:

  • "Is this a new codebase or a migration?" — the answers differ substantially.
  • "How strict are we willing to be?" — strict off removes most of the value.

Code / implementation expected: Optional. Showing a props type and a discriminated union is enough.

typescripttype safetydevelopmenttooling
02

Attempt it yourself

Sketch your approach before reading the solution — that's what interviews test.

Nudge consolestandby

Stuck? Beam a request up — the console returns a conceptual nudge that guides your logic without spoiling the implementation.

03

Study the solution

Target Audience: Engineers preparing for React interviews — assumes basic TypeScript familiarity. Difficulty: Medium

How to read this doc: Concepts are explained in plain language first, then tagged with 📌 Interview term:. Section 3 is five real compiler diagnostics, produced by running

Solution ready — 2 min read

Classified // press E to declassify

04

Explore the playground snippets

The five diagnostics, with the fixed version beside each
Run Playground
import { useState } from "react";

// This playground runs JavaScript, so none of the errors below are enforced
// here — which is precisely the point. Each row shows what plain JSX does with
// a mistake, and the exact diagnostic TypeScript produced for it.

const BADGE_TYPE = `type BadgeProps = {
  label: string;
  count: number;
  tone?: "info" | "warn";
};`;

const CASES = [
  {
    wrong: '<Badge label="items" count="3" />',
    right: '<Badge label="items" count={3} />',
    error: "TS2322: Type 'string' is not assignable to type 'number'.",
    js: "renders 'items: 3' — looks fine until you do arithmetic on it",
  },
  {
    wrong: '<Badge label="items" />',
    right: '<Badge label="items" count={0} />',
    error: "TS2741: Property 'count' is missing in type '{ label: string; }' but required in type 'BadgeProps'.",
    js: "renders 'items: ' with nothing after it",
  },
  {
    wrong: '<Badge label="items" count={n} tone="danger" />',
    right: '<Badge label="items" count={n} tone="warn" />',
    error: "TS2322: Type '\"danger\"' is not assignable to type '\"info\" | \"warn\" | undefined'.",
    js: "sets data-tone='danger', which no stylesheet matches — silently unstyled",
  },
  {
    wrong: '<Badge lable="items" count={n} />',
    right: '<Badge label="items" count={n} />',
    error: "TS2322: Property 'lable' does not exist on type 'IntrinsicAttributes & BadgeProps'. Did you mean 'label'?",
    js: "renders ': 3' — the typo is IGNORED entirely. The worst one.",
  },
  {
    wrong: 'onClick={() => setN("many")}',
    right: 'onClick={() => setN(n + 1)}',
    error: "TS2345: Argument of type 'string' is not assignable to parameter of type 'SetStateAction<number>'.",
    js: "state becomes the string 'many'; the next n + 1 gives 'many1'",
  },
];

export default function App() {
  const [i, setI] = useState(3);
  const c = CASES[i];

  return (
    <div style={{ padding: 24, fontFamily: "system-ui", lineHeight: 1.6, maxWidth: 620 }}>
      <pre style={{ background: "#eef", border: "1px solid #ccd", borderRadius: 8, padding: 10, fontSize: 12 }}>
{BADGE_TYPE}
      </pre>

      <div style={{ display: "flex", gap: 6, flexWrap: "wrap", margin: "10px 0" }}>
        {CASES.map((_, n) => (
          <button key={n} onClick={() => setI(n)} style={{ fontWeight: n === i ? "bold" : "normal" }}>
            case {n + 1}
          </button>
        ))}
      </div>

      <div style={{ border: "1px solid #ddd", borderRadius: 8, padding: 12, fontSize: 13 }}>
        <div style={{ marginBottom: 8 }}>
          <span style={{ color: "#a33" }}></span><code>{c.wrong}</code>
        </div>
        <div style={{ background: "#fdf0f0", border: "1px solid #e0b4b4", borderRadius: 6, padding: 8,
                      fontSize: 12, fontFamily: "ui-monospace, monospace", marginBottom: 8 }}>
          {c.error}
        </div>
        <div style={{ marginBottom: 8, color: "#666", fontSize: 12 }}>
          <strong>without types:</strong> {c.js}
        </div>
        <div>
          <span style={{ color: "#161" }}></span><code>{c.right}</code>
        </div>
      </div>

      <p style={{ fontSize: 13, color: "#666" }}>
        Case 4 is the one to remember. An unknown prop in JSX is not an error —
        it is simply dropped, so the component renders with a missing label and
        nothing anywhere tells you. Every diagnostic above was produced by
        actually compiling this component with the wrong usage.
      </p>
    </div>
  );
}
05

Join the discussion

Discussion (0)

Sign in to join the discussion.

No responses yet. Be the first to share what you think.

Transmission complete // awaiting log

KEEP THE
STREAK ALIVE.

Dossier 59 of 119 decoded in the React.js track. One more won't hurt.

Back to track