imsunhao / nextjs-routes

Type safe routing for Next.js

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Next.js Routes

Type safe routing for Next.js


nextjs-routes preview gif

What is this? 🧐

A code generation tool to make next/link and next/router routes type safe with zero runtime overhead. nextjs-routes scans your pages directory and generates a nextjs-routes.d.ts file with type definitions for all your routes.

Installation & Usage πŸ“¦

  1. Add this package to your project:

    npm install nextjs-routes or yarn add nextjs-routes

  2. Update your next.config.js:

    + const { withRoutes } = require("nextjs-routes/next-config.cjs");
    
    /** @type {import('next').NextConfig} */
    const nextConfig = {
      reactStrictMode: true,
    };
    
    - module.exports = nextConfig;
    + module.exports = withRoutes(nextConfig);

    This wiring will only run in Next.js' development server (eg npx next dev) and withRoutes will no-op in production.

  3. Start your next server:

    npx next dev or yarn next dev

That's it! A nextjs-routes.d.ts file will be generated the first time you start your server. Check this file into version control. next/link and next/router type definitions have been augmented to verify your application's routes. No more broken links, and you get route autocompletion πŸ™Œ.

Whenever your routes change, your nextjs-routes.d.ts file will automatically update.

Highlights

πŸ¦„ Zero config

πŸ’¨ Types only -- zero runtime

πŸ›  No more broken links

πŸͺ„ Route autocompletion

πŸ”— Supports all Next.js route types: static, dynamic, catch all and optional catch all

Examples πŸ› 

Link

Link's href prop is now typed based on your application routes and expects a URL object:

import Link from "next/link";

function Home() {
  return (
    <Link
      href={{
        pathname: "/foos/[foo]",
        query: { foo: "test" },
      }}
    >
      <a>About us</a>
    </Link>
  );
}

export default Home;

useRouter

useRouter's returned router instance types for push, replace and query are now typed based on your application routes.

Identical to Link, push and replace now expect a URL object:

push

import { useRouter } from "next/link";

const router = useRouter();
router.push({ pathname: "/foos/[foo]", query: { foo: "test" } });

replace

import { useRouter } from "next/link";

const router = useRouter();
router.replace({ pathname: "/" });

query

import { useRouter } from "next/link";

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

By default, query will be typed as the union of all possible query parameters defined by your application routes. If you'd like to narrow the type to fewer routes or a single page, you can supply a type argument:

import { useRouter } from "next/link";

// query is now typed as `{ foo: string }`
const { query } = useRouter<"/foos/[foo]">();

Route

If you want to use the generated Route type in your code, you can import it from nextjs-routes:

import type { Route } from "nextjs-routes";

How does this work? πŸ€”

nextjs-routes generates types for the pathname and query for every page in your pages directory. The generated types are written to nextjs-routes.d.ts which is automatically referenced by your Next project's tsconfig.json. nextjs-routes.d.ts redefines the types for next/link and next/router and applies the generated route types.

What if I need a runtime?

There are some cases where you may want to generate a type safe path from a Route object, such as when fetching from an API route or serving redirects from getServerSideProps. These accept strings instead of the Route object that Link and useRouter accept. Because these do not perform the same string interpolation for dynamic routes, runtime code is required instead of a type only solution.

For these cases, you can use route from nextjs-routes:

fetch

import { route } from "nextjs-routes";

fetch(route({ pathname: "/api/foos/[foo]", query: { foo: "foobar" } }));

getServerSideProps

import { route } from "nextjs-routes";

export const getServerSideProps: GetServerSideProps = async (context) => {
  return {
    redirect: {
      destination: route({ pathname: "/foos/[foo]", query: { foo: "foobar" } }),
      permanent: false,
    },
  };
};

Contributing πŸ‘«

PR's and issues welcomed! For more guidance check out CONTRIBUTING.md

Licensing πŸ“ƒ

See the project's MIT License.

About

Type safe routing for Next.js

License:MIT License


Languages

Language:TypeScript 93.6%Language:JavaScript 5.9%Language:Shell 0.5%