next-type-router
🔬 An experiment to make next.js router usage safer.
Heavily inspired by my work on @swan-io/chicane
Installation
$ yarn add next-type-router
$ npm install --save next-type-router
Quickstart
First, you have to generate the typed router functions. For that, I recommend using npm scripts:
"scripts": {
"type-router": "type-router src/router.ts",
"dev": "yarn type-router && next dev",
"build": "yarn type-router && next build",
When ran, this command parse your pages tree and generates a TS file (src/router.ts) which looks like this:
import { createTypedFns } from "next-type-router";
export const {
createURL,
getApiRequestParams,
getServerSideParams,
useRouterWithSSR,
useRouterWithNoSSR,
} = createTypedFns([
"/",
"/api/auth/login",
"/api/projects/[projectId]",
"/projects",
"/projects/[projectId]",
"/users",
"/users/[userId]",
"/users/[userId]/favorites/[[...rest]]",
"/users/[userId]/repositories",
"/users/[userId]/repositories/[repositoryId]",
]);
API
createURL
import Link from "next/link";
import { createURL } from "path/to/router";
export default function ExamplePage() {
return (
<>
<h1>Users</h1>
{/* URL params are type safe! */}
<Link href={createURL("/users/[userId]", { userId: "zoontek" })}>
zoontek
</Link>
</>
);
}
useRouterWithSSR
import { useRouterWithSSR } from "path/to/router";
export default function ExamplePage() {
const { params } = useRouterWithSSR("/users/[userId]");
const { userId } = params.route;
return <h1>{userId} profile</h1>;
}
useRouterWithNoSSR
import { useRouterWithNoSSR } from "path/to/router";
export default function ExamplePage() {
const { params } = useRouterWithNoSSR("/users/[userId]");
const { userId } = params.route;
if (userId == null) {
return <span>Loading…</span>;
}
return <h1>{userId} profile</h1>;
}
getApiRequestParams
import type { NextApiRequest, NextApiResponse } from "next";
import { getApiRequestParams } from "path/to/router";
export default function handler(req: NextApiRequest, res: NextApiResponse) {
const params = getApiRequestParams("/api/projects/[projectId]", req);
res.status(200).json({ handler: "project", params });
}
getServerSideParams
import { GetServerSideProps } from "next";
import Link from "next/link";
import { getServerSideParams } from "path/to/router";
export const getServerSideProps: GetServerSideProps = async (context) => {
const params = getServerSideParams("/users/[userId]", context);
console.log(params.route.userId);
return { props: {} };
};
Error handling
What happen when I, let's say, use useRouterWithSSR("/users/[userId]") in page with /project/[projectId] path?
Well, it will throw an error đź’Ą. That's why I highly recommand to create a 500.tsx page and wrap your app in an Error Boundary.
