Introduction
If you're like me, a Typescript fanatic, you always want to take advantage of all the cool things it can do to improve your code and make it easier to maintain. After all, that's what most developers are striving for.
Until recently, Next.js did not provide a built-in mechanism for ensuring type safety in its routing system. Unfortunately, this implies we needed a method to ensure the path we provide to Link
is valid.
Next.js has implemented a new feature in version 13.2 that introduces static typing for links within the app directory. This feature aims to prevent typographical errors or potential issues that may arise when utilizing next/link
.
Let's explore how we can implement this feature in a next.js app.
Setting up a Next.js app
Imagine our application consisting of three routes, a home page, a contact page, and an about page.
Since the routing system in the app directory is managed based on the folders contained within it. Structure the app folder as follows:
Let's create a simple navigation within the layout.tsx
file so we can navigate between our defined pages.
import Link from 'next/link';
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
<header>
<h1><Link href="/">Next.js 13</Link></h1>
<nav>
<ul>
<li><Link href={'/contact'}>Contact</Link></li>
<li><Link href={'/about'}>About</Link></li>
</ul>
</nav>
</header>
{children}
</body>
</html>
);
}
import Link from 'next/link';
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
<header>
<h1><Link href="/">Next.js 13</Link></h1>
<nav>
<ul>
<li><Link href={'/contact'}>Contact</Link></li>
<li><Link href={'/about'}>About</Link></li>
</ul>
</nav>
</header>
{children}
</body>
</html>
);
}
To demonstrate how statically typed routes work, let's add a new navigation item that currently does not exist in our app. This way, we can simulate how the static typing feature can resolve such a scenario.
<header>
<h1><Link href="/">Next.js - Statically typed links</Link></h1>
<nav>
<ul>
<li><Link href={'/contact'}>Contact</Link></li>
<li><Link href={'/about'}>About</Link></li>
<li><Link href={'/blog'}>Blog</Link></li>
</ul>
</nav>
</header>
<header>
<h1><Link href="/">Next.js - Statically typed links</Link></h1>
<nav>
<ul>
<li><Link href={'/contact'}>Contact</Link></li>
<li><Link href={'/about'}>About</Link></li>
<li><Link href={'/blog'}>Blog</Link></li>
</ul>
</nav>
</header>
By default, TypeScript will not complain about errors related to the non-existent route during build time. You won't receive any warnings in your text editor either (as shown in the screenshot below).
This lack of type safety could lead to errors and bugs in the application.
Experimental typed routes
Enabling this feature is easy to set up; add typedRoutes: true
under the experimental
field in your next.config.js file.
const nextConfig = {
experimental: {
typedRoutes: true,
...
},
...
};
const nextConfig = {
experimental: {
typedRoutes: true,
...
},
...
};
When typedRoutes
is true
, Next.js will create a type corresponding to all possible paths in our application's link definition within the build source.
Since I'm using the 13.4 version on Next.js, I don't need to add appDir
under the experimental
field since it's finally stable and can be adopted for production. However, If you're using an earlier version, you must include it.
const nextConfig = {
experimental: {
appDir: true,
typedRoutes: true,
...
},
...
};
const nextConfig = {
experimental: {
appDir: true,
typedRoutes: true,
...
},
...
};
Now that TypeScript can leverage the link definition file, it can provide feedback within your text editor to help catch any invalid links before you ship to production.
Statically type links for older versions
If you're Next.js application is running on an older version than 13.2
, you can use the open-source next-routes package, which can also generate the route types with zero configuration.
Install this package by running the following command:
# npm
npm install nextjs-routes
# yarn
yarn add nextjs-routes
# pnpm
pnpm add nextjs-routes
# npm
npm install nextjs-routes
# yarn
yarn add nextjs-routes
# pnpm
pnpm add nextjs-routes
Update the next.config.js file to merge next-routes
with the Next.js config.
const nextRoutes = require("nextjs-routes/config");
const withRoutes = nextRoutes();
const nextConfig = {
...
};
module.exports = withRoutes(nextConfig);
const nextRoutes = require("nextjs-routes/config");
const withRoutes = nextRoutes();
const nextConfig = {
...
};
module.exports = withRoutes(nextConfig);
Conclusion
With our new statically typed routes in place, we can now make changes to our app's folder structure without worrying much about breaking things in the production.
While this is still an experimental feature, it is worth exploring if you want to make the most of TypeScript.