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.

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 getStaticProps
, getServerSideProps
, getStaticPaths
, 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.
Error | Cause | Fix |
---|---|---|
Object is possibly ‘null’ | Missing null checks | Use optional chaining or conditional logic |
JSX element type does not have any construct or call signatures | Incorrectly typed component | Ensure default exports & correct generics |
Type ‘undefined’ is not assignable | Accessing context or optional prop | Add 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.