Next.js Using TypeScript
TypeScript is JavaScript with types. It adds a layer of safety to your code by letting you define exactly what kind of data a variable, function parameter, or component prop expects. Next.js has built-in TypeScript support — no extra plugins needed.
Why Use TypeScript
JavaScript lets you pass any value anywhere. TypeScript catches mismatches before your code runs. This prevents entire categories of bugs that would otherwise only appear in production.
JAVASCRIPT (no type safety):
function greet(user) {
return 'Hello, ' + user.name;
}
greet(42); // No error shown, but crashes at runtime: 42.name is undefined
TYPESCRIPT (type safety):
function greet(user: { name: string }) {
return 'Hello, ' + user.name;
}
greet(42); // Error shown immediately: Argument of type 'number' is not assignable
Setting Up TypeScript in Next.js
When you create a new project with create-next-app, select "Yes" when asked about TypeScript. The setup is complete automatically.
For an existing JavaScript project, rename your files from .js to .ts (or .tsx for files containing JSX). Then run:
npm install --save-dev typescript @types/react @types/node
Start the development server once. Next.js creates a tsconfig.json file automatically.
File Extensions
.js → JavaScript (no types) .ts → TypeScript (no JSX) .tsx → TypeScript with JSX (use this for React components) .jsx → JavaScript with JSX
Typing Component Props
Define the shape of your component's props using a TypeScript type or interface. This tells TypeScript and your editor exactly what values the component expects.
// Without TypeScript:
function Button({ label, onClick, disabled }) { ... }
// With TypeScript:
type ButtonProps = {
label: string;
onClick: () => void;
disabled?: boolean; // The ? means this prop is optional
};
export default function Button({ label, onClick, disabled }: ButtonProps) {
return (
<button onClick={onClick} disabled={disabled}>
{label}
</button>
);
}
DIAGRAM: TypeScript Catching a Prop Error
<Button label={42} />
↑
TypeScript error: Type 'number' is not assignable to type 'string'
Error shown in editor before code even runs
Typing Page Props (params and searchParams)
Next.js pages receive params and searchParams as props. Type them explicitly to avoid errors when accessing their values.
// app/blog/[slug]/page.tsx
type Props = {
params: {
slug: string;
};
searchParams: {
[key: string]: string | string[] | undefined;
};
};
export default async function BlogPost({ params, searchParams }: Props) {
const post = await fetchPost(params.slug);
return <article>{post.title}</article>;
}
Typing API Routes
// app/api/users/route.ts
import { NextRequest, NextResponse } from 'next/server';
type User = {
id: number;
name: string;
email: string;
};
export async function GET(request: NextRequest): Promise<NextResponse<User[]>> {
const users: User[] = await fetchUsers();
return NextResponse.json(users);
}
Common TypeScript Patterns in Next.js
Typing useState
const [user, setUser] = useState<User | null>(null); const [count, setCount] = useState<number>(0); const [items, setItems] = useState<string[]>([]);
Typing Event Handlers
function handleInput(event: React.ChangeEvent<HTMLInputElement>) {
console.log(event.target.value);
}
function handleSubmit(event: React.FormEvent<HTMLFormElement>) {
event.preventDefault();
}
Typing Async Data
type Post = {
id: number;
title: string;
body: string;
};
async function fetchPost(slug: string): Promise<Post> {
const res = await fetch(`/api/posts/${slug}`);
return res.json();
}
The tsconfig.json File
Next.js generates a tsconfig.json with sensible defaults. You rarely need to edit it. The most important setting is strict: true, which turns on all of TypeScript's strictest checks. Keep this enabled — it catches more bugs.
{
"compilerOptions": {
"strict": true, ← Keep this enabled
"target": "ES2017",
"lib": ["dom", "esnext"],
"module": "esnext",
"jsx": "preserve",
"paths": {
"@/*": ["./*"] ← Enables @/components shortcut imports
}
}
}
TypeScript Does Not Slow Your App
TypeScript types exist only during development. The TypeScript compiler strips all type annotations before running the code. Your production app runs plain JavaScript — TypeScript has zero runtime cost.
DEVELOPMENT:
TypeScript code → TypeScript compiler checks types → Shows errors immediately
PRODUCTION BUILD:
TypeScript code → Types stripped out → Plain JavaScript runs
↑ No performance difference from JavaScript
Key Takeaway
TypeScript adds type safety to your Next.js code, catching bugs before they reach users. Use .tsx files for React components and .ts for non-JSX TypeScript. Define prop types with type or interface. Type your page props, API routes, and async functions. TypeScript types disappear at runtime, so there is no performance cost in production.
