If you're starting a Next.js project, it probably came with TypeScript turned on. That can feel scary if you've only written plain JavaScript.
The whole language is a lot. The part you need for Next.js is about seven small ideas, and this post sticks to those, with tiny examples. Ten minutes, tops.
TypeScript is just JavaScript with labels on your data. The labels tell your editor what a value is, so it can catch mistakes before you even run the code.
1. Basic types
You add a type after a colon. That's the whole syntax.
const name: string = "Sara";
const age: number = 25;
const isAdmin: boolean = false;
const tags: string[] = ["next", "react"];
Most of the time you can skip the type and TypeScript figures it out:
const name = "Sara"; // TypeScript already knows this is a string
2. Describing objects
For objects, you describe the shape once with type, then reuse it.
type User = {
name: string;
age: number;
};
const sara: User = { name: "Sara", age: 25 };
Now if you forget age or spell name wrong, your editor underlines it in red.
You'll also see interface User { ... }. For beginners, it does the same job as type. Pick one and don't worry about it.
3. Typing component props
This is the thing you'll do most in Next.js. Props are just an object, so you describe them the same way.
type ButtonProps = {
label: string;
onClick: () => void;
};
export default function Button({ label, onClick }: ButtonProps) {
return <button onClick={onClick}>{label}</button>;
}
() => void means "a function that takes nothing and returns nothing."
Now when you write <Button /> somewhere and forget label, Next.js tells you right in the editor instead of showing a broken button in the browser.
4. Optional and "one of these" types
A ? after a name means "this is optional."
A | means "one of these values."
type ButtonProps = {
label: string;
variant?: "primary" | "secondary"; // optional, and only these two words
};
Now <Button label="Save" /> works, and <Button label="Save" variant="big" /> gets a red underline. You get autocomplete for variant too.
5. Typing state
useState usually guesses the type from the starting value, so this just works:
const [count, setCount] = useState(0); // number
It only needs help when it starts empty. Tell it what will go in using angle brackets:
const [user, setUser] = useState<User | null>(null);
That reads as "this state holds a User, or nothing yet." Angle brackets are how you pass a type to a function.
Don't forget "use client" at the top of any file that uses useState in Next.js.
6. Typing data you fetch
When you fetch from an API, TypeScript has no idea what comes back, so you have to tell it.
type Post = {
id: number;
title: string;
};
async function getPosts(): Promise<Post[]> {
const res = await fetch("https://api.example.com/posts");
return res.json();
}
Promise<Post[]> means "this async function will eventually give you a list of posts."
After that, anywhere you use posts, your editor knows each one has an id and a title.
7. The two Next.js-specific bits
Page params
In the App Router, a page like app/blog/[slug]/page.tsx gets its slug through params. Since Next.js 15, params is a Promise, so you type it like this and await it:
export default async function BlogPost({
params,
}: {
params: Promise<{ slug: string }>;
}) {
const { slug } = await params;
return <h1>{slug}</h1>;
}
If you see old tutorials with params: { slug: string } and no await, that's the pre-15 way. It will show a type error on current versions.
Metadata
Next.js ships its own types. The one you'll meet first is Metadata for your page title:
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "My Blog",
};
Adding : Metadata gets you autocomplete for every allowed field, which is most of the reason to use the built-in types at all.
That's it
Those seven ideas cover most of what you'll write as a beginner.
Two tips for the road:
- When you're stuck, hover over the red underline. The error message usually says exactly what's missing.
- Avoid
any. It turns TypeScript off for that value, which hides the mistakes you wanted it to catch.
Everything else (generics, utility types, type guards) can wait until you actually need it. Build something first.
What tripped you up when you first used TypeScript with Next.js? Drop it in the comments.
Top comments (0)