TypeScript with React
โš›๏ธ React 18+ ๐ŸŸข Chapter 37 of 39 ๐Ÿ“‚ Phase 16: TypeScript with React ๐Ÿ“… 2026 Edition
๐Ÿ“Œ Covered in this chapter: .tsx Files ยท Component Props Types ยท Event Types ยท State Types ยท useRef Types ยท useReducer Types ยท API Response Types ยท Context Types
With plain TypeScript fundamentals covered, this chapter applies them specifically to React โ€” typing props, state, events, and the hooks you've used throughout this course.
1Typing Component Props
๐Ÿ’ป Example 1: A Fully Typed Component
TSX
interface UserCardProps {
  name: string;
  role: string;
  isOnline?: boolean;
}

function UserCard({ name, role, isOnline = false }: UserCardProps) {
  return (
    <div>
      <h3>{name}</h3>
      <p>{role}</p>
      <p>{isOnline ? "๐ŸŸข Online" : "โšซ Offline"}</p>
    </div>
  );
}

<UserCard name="Meera" role={42} />   // โŒ TypeScript error - role must be a string
๐Ÿ” The Payoff:

This is the direct TypeScript upgrade of Chapter 8's Props chapter โ€” instead of discovering a wrong prop type as a confusing bug at runtime, your editor flags it immediately while you're still typing the JSX.

2Typing State and Event Handlers
import { useState, ChangeEvent, FormEvent } from "react";

interface FormData {
  email: string;
  age: number;
}

function SignupForm() {
  const [form, setForm] = useState<FormData>({ email: "", age: 0 });

  function handleChange(e: ChangeEvent<HTMLInputElement>) {
    setForm({ ...form, [e.target.name]: e.target.value });
  }

  function handleSubmit(e: FormEvent<HTMLFormElement>) {
    e.preventDefault();
    console.log(form);
  }

  return <form onSubmit={handleSubmit}><input name="email" onChange={handleChange} /></form>;
}

useState<FormData> tells TypeScript exactly what shape the state object has, catching any mismatched update. ChangeEvent<HTMLInputElement> and FormEvent<HTMLFormElement> give you fully typed access to e.target.value and e.preventDefault() from Chapters 11 and 14.

3Typing useRef and API Responses
import { useRef } from "react";

function SearchBox() {
  const inputRef = useRef<HTMLInputElement>(null);
  return <input ref={inputRef} />;
}

// Typing a fetched API response (from Chapter 21)
interface User {
  id: number;
  name: string;
}

async function getUsers(): Promise<User[]> {
  const res = await fetch("/api/users");
  return res.json();
}

useRef<HTMLInputElement>(null) tells TypeScript exactly which native DOM methods are available on inputRef.current (like .focus()). Typing your API's response shape means every place you use that fetched data gets full autocomplete and error-checking, catching typos in field names (like user.naem) immediately.

4Typing Context
interface AuthContextType {
  username: string | null;
  login: (name: string) => void;
}

const AuthContext = createContext<AuthContextType | null>(null);

function useAuth() {
  const context = useContext(AuthContext);
  if (!context) throw new Error("useAuth must be used inside AuthProvider");
  return context;
}

This pattern โ€” a typed Context plus a custom hook (combining Chapters 24 and 29) that throws a clear error if used outside its Provider โ€” is the standard, professional way to type Context in real TypeScript + React projects.

โš ๏ธ Typing Props with 'any' Instead of a Real Interface

Writing function UserCard(props: any) compiles, but throws away every benefit TypeScript offers for that component โ€” no autocomplete, no error checking on what's passed in. Always define a real interface for a component's props, even a very simple one; it takes seconds and pays for itself the first time you catch a typo.

๐Ÿ’ป Hands-on Interactive Practice Challenge

Define a typed Props interface for a ProductCard component (name: string, price: number, inStock: boolean) and use it to type the component.

React Practice Challenge โ–ถ Run in Compiler
interface ProductCardProps {
  name: string;
  price: number;
  inStock: boolean;
}

function ProductCard({ name, price, inStock }: ProductCardProps) {
  return (
    <div>
      <h3>{name}</h3>
      <p>${price}</p>
      <p>{inStock ? "In Stock" : "Sold Out"}</p>
    </div>
  );
}
Run This Challenge in Online JS IDE โ†’
โ“ Frequently Asked Questions (FAQ)

Q What's the difference between a .jsx file and a .tsx file?

A .tsx file is a TypeScript file that's allowed to contain JSX syntax (component markup) โ€” it's compiled the same way, but TypeScript type-checks everything in it. Plain .ts files can't contain JSX at all.

Q Do I need to type every single useState call?

Not always โ€” TypeScript can often infer the type automatically from the initial value, e.g. useState(0) is automatically typed as a number. Explicit typing (useState(...)) is mainly needed when the initial value doesn't fully describe the type, like starting with null or an empty object.

OC
Written by Our Compiler Technical Editorial Team
Reviewed for accuracy & tested on React 18+ ยท Last updated August 2026