Skip to the solution
MediumFrontend7 min read

Describe the benefits of using TypeScript with React.

469 views

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.

  • typescript
  • type safety
  • development
  • tooling

Try it yourself

Sketch your approach before you read the solution. That is what the interview tests.

Stuck? Get a hint.

A short nudge toward the approach. It will not give the answer away.

Solution

The solution is hidden so you can try first

7 min read Β· 9 sections

Try it in the playground

Open any example in the playground to run and change it.

ReactThe five diagnostics, with the fixed version beside each
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>
  );
}

Discussion

Other approaches, follow-ups and how it went in real interviews.

Sign in to join the discussion.

No comments yet. Share how you would answer it.

Question 59 of 119 in React.js

Keep your momentum going.

Mark this question solved to track your progress, then take the next one while it is fresh.

All React.js questions
Up nextMedium

What are Higher-Order Components (HOCs) in React?

Continue