Stop 07 · TypeScript Across the StackTopics · 6/7

TypeScript with React

Part of the Full Stack Developer Roadmap

In short

Most React bugs are a wrong or missing prop, or state that's sometimes null. TypeScript turns those into red squiggles while you type, and gives you autocomplete on every prop.

Typing component props, state, event handlers and hooks — catching a huge class of frontend bugs (wrong prop types, missing required props) before they ever reach the browser.

The mascot feeds a photo into an ID card printer with shaped slots.

Think of it like this

The ID card printing machine

The college ID machine has a square slot for the photo and a long one for the details card. Try to feed it without a photo and it simply won't start. A typed component works like that: miss a required prop and it won't compile.

Watch it happen

The compiler reviews a prop

ShopPage
ProductCard
TS checker

name="Pen", no price

1/5ShopPage renders a card but forgets price and onAdd.

The big ideas

What you need to know

Type props with a type or interface

Destructure in the parameter: ({ name, price }: ProductCardProps). Optional props get a ?.

Hint useState when it starts empty

useState(0) infers number. useState<User | null>(null) needs the hint, then TS makes you check for null.

Event types

Use ChangeEvent<HTMLInputElement> or FormEvent<HTMLFormElement>. Hover the handler in VS Code to see the right one.

children is ReactNode

For wrappers, type children as React.ReactNode so it accepts text, elements, lists or null.

See it in code

Walk through the code

tsx
1import { useState, type ChangeEvent } from "react";2type ProductCardProps = {3  id: number;4  name: string;5  price: number;6  badge?: "new" | "sale";7  onAdd: (id: number, qty: number) => void;8};9export function ProductCard({ id, name, price, badge, onAdd }: ProductCardProps) {10  const [qty, setQty] = useState(1); // inferred as number11  const handleQty = (e: ChangeEvent<HTMLInputElement>) => setQty(Number(e.target.value));12  return <div>{name} ₹{price} {badge && <span>{badge}</span>}13    <input type="number" min={1} value={qty} onChange={handleQty} />14    <button onClick={() => onAdd(id, qty)}>Add</button>15  </div>;16}

1/4The props contract: badge is optional and limited to two values, onAdd's signature is fixed.

The props type doubles as documentation. Anyone using ProductCard sees exactly what it needs.

Save yourself the pain

Common mistakes

Oops

Typing props as any or skipping the type 'for now'.

Do this instead

Write the props type first. It takes a minute and catches every wrong usage across the app.

Oops

useState([]) and later pushing objects, getting 'never[]' errors.

Do this instead

Give an empty array a type: useState<Product[]>([]).

Your mission

Type a small shop page

~30 min

Quick check

You write const [user, setUser] = useState(null). Later setUser({ name: "Riya" }) shows an error. Why?

Go deeper

  1. 1Convert one React component to TypeScript, typing its props explicitly.
  2. 2Learn how to type `useState`, `useRef` and event handlers correctly.
  3. 3Type a custom hook's return value so consumers get full autocomplete.

More topics at this stop

Stuck on this topic? Ask an Insider

Get 1:1 guidance from people who've walked this exact path — on the InsideEdge app.

Download
InsideEdge