Bits Kingdom logo with a hexagon lattice, uppercase text in white, and a minimalistic design.

Strictly Typed: TypeScript with React & Next.js. Real-World Usage

From Zero to Production-Ready Code - Chapter 6

Home / Development / Strictly Typed: TypeScript with React & Next.js. Real-World Usage

When TypeScript meets React and Next.js, the result is a developer experience that’s both productive and safe. Over the years, working on full-stack projects, I’ve found that combining these three technologies not only boosts confidence in my code but also helps teams move faster without sacrificing quality. In this chapter, we’ll explore how to type your React components, hooks, context, and events, as well as how to configure Next.js API routes and pages with TypeScript for a modern full-stack workflow.

3D TypeScript logo for a series of posts.

1. Setting Up TypeScript in React and Next.js Projects

Learn how to configure TypeScript for new and existing React apps, as well as how to enable full TypeScript support in Next.js with auto-generated configuration.

React Project

If you’re using Create React App:

npx create-react-app my-app --template typescript

Or for an existing project:

npm install --save-dev typescript @types/react @types/react-dom

Rename .js files to .tsx.

Next.js Project

With TypeScript built-in:

npx create-next-app@latest my-app --typescript

Or manually add:

npm install --save-dev typescript @types/react @types/node

Next.js will auto-generate a tsconfig.json on first run.

2. Typing React Components and Props in TypeScript

Master typing functional components, props, children, and default props for reliable UI development.

Functional Components with Props

type ButtonProps = {
  label: string;
  onClick: () => void;
};

const Button = ({ label, onClick }: ButtonProps) => (
  <button onClick={onClick}>{label}</button>
);

Or with React.FC:

const Button: React.FC<ButtonProps> = ({ label, onClick }) => (
  <button onClick={onClick}>{label}</button>
);

Note: React.FC adds children by default and infers return type.

Optional & Default Props

type AlertProps = {
  message: string;
  type?: "info" | "error";
};

const Alert = ({ message, type = "info" }: AlertProps) => (
  <div className={`alert-${type}`}>{message}</div>
);

Typing children

type LayoutProps = {
  children: React.ReactNode;
};

const Layout = ({ children }: LayoutProps) => <main>{children}</main>;

3. Typing React State and Event Handlers in TypeScript

Define types for component state and events to ensure safer state management and predictable interactions.

useState with Types

const [count, setCount] = useState<number>(0);

Or infer from initial value:

const [message, setMessage] = useState("Hello"); // inferred as string

Typing Events

const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
  console.log(e.target.value);
};

4. Typing Custom React Hooks with TypeScript

Write reusable custom hooks by explicitly typing parameters and return values.

function useToggle(initial: boolean): [boolean, () => void] {
  const [state, setState] = useState(initial);
  const toggle = () => setState((prev) => !prev);
  return [state, toggle];
}

5. Typing React Context in TypeScript Applications

Properly type your React Context providers and consumers to avoid common runtime issues.

type Theme = "light" | "dark";

type ThemeContextType = {
  theme: Theme;
  toggleTheme: () => void;
};

const ThemeContext = createContext<ThemeContextType | undefined>(undefined);

export const ThemeProvider = ({ children }: { children: React.ReactNode }) => {
  const [theme, setTheme] = useState<Theme>("light");
  const toggleTheme = () =>
    setTheme((prev) => (prev === "light" ? "dark" : "light"));

  return (
    <ThemeContext.Provider value={{ theme, toggleTheme }}>
      {children}
    </ThemeContext.Provider>
  );
};

Usage:

const theme = useContext(ThemeContext);
if (!theme) throw new Error("Must be used within ThemeProvider");

6. Typing Next.js Pages and API Routes with TypeScript

Use built-in Next.js TypeScript support to strongly type getStaticPropsgetServerSidePropsgetStaticPaths, and API endpoints.

Pages

Next.js automatically types getStaticProps, getServerSideProps, and getStaticPaths:

import { GetStaticProps } from "next";

export const getStaticProps: GetStaticProps = async () => {
  return { props: { message: "Hello" } };
};

API Routes

import type { NextApiRequest, NextApiResponse } from "next";

export default function handler(
  req: NextApiRequest,
  res: NextApiResponse<{ message: string }>
) {
  res.status(200).json({ message: "API success" });
}

7. Typing Props from Next.js Data Fetching Functions

Infer and enforce prop types from server-side and static data functions for more robust applications.

type Props = {
  post: {
    id: number;
    title: string;
  };
};

export const getStaticProps: GetStaticProps<Props> = async () => {
  const post = { id: 1, title: "Hello World" };
  return { props: { post } };
};

const Page = ({ post }: Props) => <h1>{post.title}</h1>;

8. Solving Common TypeScript Errors in React and Next.js Projects

Recognize frequent typing errors when working with React and Next.js, and learn how to resolve them effectively.

ErrorCauseFix
Object is possibly ‘null’Missing null checksUse optional chaining or conditional logic
JSX element type does not have any construct or call signaturesIncorrectly typed componentEnsure default exports & correct generics
Type ‘undefined’ is not assignableAccessing context or optional propAdd fallback or default value

Quick Recap

  • React + TypeScript: Always type props, state, events, and context for reliability.
  • Next.js + TypeScript: Enjoy first-class support for pages, API routes, and data-fetching functions.
  • Developer Confidence: TypeScript integrates seamlessly into React and Next.js, making your codebase safer and easier to maintain.

Coming up next: Configuring and Testing TypeScript Projects—learn how to set up tsconfig, ESLint, Prettier, and testing frameworks like Jest or Testing Library for a professional development workflow.

About the author

<a href="https://bitskingdom.com/blog/author/enrique/" target="_self">Enrique Sarmiento</a>
Enrique Sarmiento
I’m a Full-Stack Developer with 5+ years of experience developing web and cross-platform mobile applications, specializing in eCommerce and advanced technology features. I’m skilled in software development lifecycles and testing methodologies, with substantial experience building high-performing, scalable, and enterprise-grade applications in both Node.js and Swift environments.

Explore more topics:

If It’s Something, Let It Be Something: UX Design Lessons

A visual principle that transforms how you design.