Chris.luChris.lu header image, displaying an 80s style landscape and sunset

Typescript plugin and typed routes

The next step is to ensure Typescript is correctly set up, and we will also enable an interesting feature called statically typed routes

Next.js typescript plugin

Since Next.js 13.1, the Next.js team added a new Typescript plugin:

We've built a new TypeScript plugin that provides suggestions for page and layout configuration options and provides helpful usage hints around Server and Client Components

Delba de Oliveira, which is part of the Next.js developer experience team, posted a short "Next.js Typescript plugin" introduction video on Youtube that you may want to watch

Enabling the Next.js Typescript plugin

To make the Next.js typescript plugin work, you need to make sure that the Typescript version that VSCode is using is the workspace version (the version that Next.js create app just installed) because, by default, VSCode will use a built-in Typescript version.

If you don't know yet how to change the typescript version to workspace version (in VSCode), check out the VSCode typescript version chapter in the VSCode post

As soon as you switch to the workspace version, VSCode will create a new .vscode/settings.json file (or if you already have a VSCode settings.json, it will extend it), there is nothing wrong in sharing that file as it will ensure that everyone that works on your project (or if you use multiple devices yourself) will use the same workspace settings, like the typescript workspace version but also other settings, for example in one of the following chapters we will add helpful VSCode extension and VSCode will be listing in settings file, so that if someone works on your project but does not have the extension installed VSCode will show a modal that suggests installing it.

Tip

The Next.js typescript plugin comes with some useful features. It will for example, warn you if something is wrong in how you use the use client directive in your components and some more. I recommend keeping an eye on the Next.js "typescript" documentation as the Next.js team adds more features over time

Finally, I recommend you commit/sync the new .vscode/settings.json.

Warning

There seems to be a bug in the route types for *.mdx pages. When doing a dev build, all routes are typed and listed in the .next/types/link.d.ts, but when doing a prod build, they are NOT getting added in the .next/types/link.d.ts file, resulting in a Type error "XY is not an existing route.", there is a fix in the works but it is only in the canary releases (as of now, august 2024), head over to the next chapter to learn how to bypass this bug and still use the typed routes, as soon as the fix gets released this workaround will NOT be needed anymore

To ensure we benefit from statically typed links we need to enable the feature in our Next.js configuration file

Open the next.config.mjs and then add the experimental typedRoutes to your Next.js configuration file like so:

next.config.mjs
/** @type {import('next').NextConfig} */
const nextConfig = {
    experimental: {
        // experimental typescript "statically typed links"
        // https://nextjs.org/docs/app/api-reference/next-config-js/typedRoutes
        // currently false in prod until Issue #62335 is fixed
        // https://github.com/vercel/next.js/issues/62335
        typedRoutes: true,
    },
};
 
export default nextConfig

Line 1: you can see that the Next.js configuration file uses jsdoc with the @type tag, which allows us to have types even though the configuration file is not Typescript (but Javascript), which means if you start typing inside of the nextConfig object you will benefit from autocompletion for the Next.js configuration options

Lines 3-9: we use the typedRoutes (experimental) option and enabled it, which means that when using npm run dev or when building for production, Next.js will generate a .next/types/link.d.ts file that contains information about all existing routes in our application, the advantage of this is that if we now use next/link but set the href to a route that doesn't exist we will see an error in VSCode getting displayed and builds will fail until we fix the typo in our URL

Note

You might have noticed that in the latest Next.js, the configuration file is now an ECMAScript module (ES modules / ESM) and not a CommonJS module like in previous versions, which is why the extension is now .mjs and not .js anymore

This means that instead of using a require function to import other modules we now use the same import statement we use in client code, this change also matters because more and packages on npm are migrating to an ESM only format, which reduces the amount of code needed as they can drop CommonJS backward compatibility, but for us, it means we must use import statements and can't NOT use the require function anymore

Then save your next.config.mjs and commit/sync your latest changes.

Congratulations 🎉 you just made sure your typescript support is done correctly, which is a significant milestone before starting to code, and you now also have typed routes that will further improve your DX, adding more pages to your project

If you liked this post, please consider making a donation ❤️ as it will help me create more content and keep it free for everyone

typedRoutes bug

Warning

Right now, there is a bug in Next.js that prevents MDX pages (page.mdx) from being recognized as routes when doing a production build, there is a PR that will fix this but for now it is only in canary release, if you want to use typed routes today there is a workaround that I will explain in this chapter

The workaround consists of only enabling the typedRoutes in development (and NOT in production). You can do so by using the next config phase parameter to check if the current phase is PHASE_DEVELOPMENT_SERVER

Open the next.config.mjs and change your code to this:

next.config.mjs
import { PHASE_DEVELOPMENT_SERVER } from 'next/constants.js'
 
const nextConfig = (phase) => {
 
    /** @type {import('next').NextConfig} */
    const nextConfigOptions = {
        experimental: {
            // experimental typescript "statically typed links"
            // https://nextjs.org/docs/app/api-reference/next-config-js/typedRoutes
            // currently false in prod until PR #67824 lands in a stable release
            // https://github.com/vercel/next.js/pull/67824
            typedRoutes: phase === PHASE_DEVELOPMENT_SERVER ? true : false,
        },
    }
 
    return nextConfigOptions
 
}
 
export default nextConfig

In the part of the tutorial (Next.js configuration) I will explain in more detail how phases work and why we needed to convert the configuration into a function