How to Use Typed Routes in Next.js
Tags: react, nextjs, route, typescript
Published: 2024-04-22 10:06:37

Next.js is a powerful React framework that simplifies the creation of web applications by providing a set of conventions and built-in functionalities. One of the key features of Next.js is its routing system, which allows developers to create pages and navigate between them with ease. With the introduction of typed routes, Next.js enhances the developer experience by providing type safety for routing, especially when using TypeScript.

## Understanding Typed Routes in Next.js

Typed routes in Next.js are an experimental feature that provides statically typed links within your application. This feature is part of the Next.js App Router and requires TypeScript to be used in your project. The main advantage of typed routes is that they help ensure that the links within your application are correct at compile time, reducing the likelihood of runtime errors due to incorrect URLs or missing query parameters.

To enable typed routes in your Next.js project, you need to set the `typedRoutes` option to `true` in your `next.config.js` file. Here's an example configuration:

```javascript
// next.config.js
const nextConfig = {
  experimental: {
    typedRoutes: true,
  },
};

module.exports = nextConfig;
```

This feature is still in beta and currently does not support rewrites and redirects. However, it is a significant step towards improving type safety in Next.js applications.

## Using `nextjs-routes` for Typed Routing

While the built-in typed routes feature in Next.js is still experimental, there is a third-party library called `nextjs-routes` that provides type-safe routing for both the app directory and pages. This library scans your pages directory and generates route types based on your application's routes, ensuring that your links are type-safe with zero runtime overhead.

### Installation and Setup

To use `nextjs-routes`, you need to install the package and update your `next.config.js` file as follows:

```bash
npm install nextjs-routes
# or
yarn add nextjs-routes
# or
pnpm add nextjs-routes
```

Then, update your `next.config.js`:

```javascript
// next.config.js
const nextRoutes = require("nextjs-routes/config");
const withRoutes = nextRoutes();

const nextConfig = {
  reactStrictMode: true,
};

module.exports = withRoutes(nextConfig);
```

After running `npx next dev` or `npx next build`, a `@types/nextjs-routes.d.ts` file will be generated, which augments the type definitions for `next/link` and `next/router`.

### Examples of Typed Routing with `nextjs-routes`

Here are some examples of how you can use typed routing with `nextjs-routes`:

#### Link Component

```javascript
import Link from "next/link";

// Typed href based on your application routes
<Link
  href={{
    pathname: "/posts/[postId]",
    query: { postId: "123" },
  }}
>
  Read Post
</Link>;

// For routes without parameters, you can use a string
<Link href="/about">About Us</Link>;
```

#### useRouter Hook

```javascript
import { useRouter } from "next/router";

const router = useRouter();

// Typed push method
router.push({
  pathname: "/posts/[postId]",
  query: { postId: "456" },
});

// Typed replace method
router.replace("/");

// Typed query object
const { query } = useRouter();
// query is typed as a union of all query parameters defined by your application's routes
```

#### getServerSideProps

```javascript
import type { GetServerSidePropsContext } from "nextjs-routes";

export function getServerSideProps(
  context: GetServerSidePropsContext<"/posts/[postId]">
) {
  // context.params will include `postId` as a string
  const { postId } = context.params;
}
```

## Custom Example: Typed Blog Post Routes

Let's create a custom example to illustrate how typed routes can be used in a practical scenario. Imagine we have a blog application with dynamic routes for individual blog posts. We want to ensure that our links to these posts are type-safe.

First, we define our blog post page under the `pages/posts/[postId].tsx` file. Then, we use `nextjs-routes` to generate the typed routes.

```javascript
// pages/posts/[postId].tsx
import { useRouter } from "next/router";
import Link from "next/link";

const PostPage = () => {
  const router = useRouter();
  const { postId } = router.query as { postId: string };

  return (
    <div>
      <h1>Post {postId}</h1>
      <Link href="/posts">
        <a>Back to posts</a>
      </Link>
    </div>
  );
};

export default PostPage;
```

Now, when we link to a post, we can use the typed `href` to ensure that we pass the correct `postId`:

```javascript
// pages/posts/index.tsx
import Link from "next/link";

const PostsList = ({ posts }) => {
  return (
    <ul>
      {posts.map((post) => (
        <li key={post.id}>
          <Link
            href={{
              pathname: "/posts/[postId]",
              query: { postId: post.id },
            }}
          >
            {post.title}
          </Link>
        </li>
      ))}
    </ul>
  );
};

export default PostsList;
```

With `nextjs-routes`, if we accidentally mistype the route or forget to pass the required `postId`, TypeScript will alert us at compile time, preventing potential runtime errors.

## Conclusion

Typed routes in Next.js provide a robust way to ensure that your application's routing is type-safe, reducing the risk of errors and improving the developer experience. While the built-in typed routes feature in Next.js is still experimental, the `nextjs-routes` library offers a stable solution that works with both the app directory and pages. By following the examples provided, you can implement typed routes in your Next.js projects and enjoy the benefits of type safety in your routing logic.

Remember to keep an eye on the Next.js documentation and release notes for updates on the typed routes feature as it moves towards stability. Happy coding!