Repository: tatethurston/nextjs-routes (ts)

Issue:
Use with getServerSideProps, params may be undefined
I am using:

- "next": "13.2.4"
- "nextjs-routes": "^1.0.8"

I have the following file:

`pages/automator-configs/[label].tsx`:

```typescript
import { GetServerSideProps, InferGetServerSidePropsType } from 'next/types';
import { getAutomatorConfig } from '../../ansibleAdapter/automatorConfig';
import type { RoutedQuery } from 'nextjs-routes';

export const getServerSideProps: GetServerSideProps<{}, RoutedQuery<'/automator-configs/[label]'>> = async (
  context,
) => {
  const { label } = context.params;
  return { props: { automatorConfig: getAutomatorConfig()[label] } };
};

export default function AutomatorConfig({ automatorConfig }: InferGetServerSidePropsType<typeof getServerSideProps>) {
  return <pre className="max-h-96">{JSON.stringify(automatorConfig, null, 2)}</pre>;
}
```

However, this shows several eslint and TypeScript errors:

For the first generic in `GetServerSideProps`, eslint shows: “Don't use `{}` as a type. `{}` actually means "any non-nullish value"”. I guess this can be ignored for now.

`context.params` is resolved as:

```
(property) params?: ({
    label: string;
} & Query) | undefined
```

so I cannot do `const { label } = context.params;`, because it shows:

```
Property 'label' does not exist on type '({ label: string; } & Query) | undefined'.ts(2339)
```

In my `nextjs-routes.d.ts`, I see:

```typescript
declare module "nextjs-routes" {
  export type Route =
    | StaticRoute<"/404">
    | DynamicRoute<"/automator-configs/[label]", { "label": string }>
    | StaticRoute<"/">;

  interface StaticRoute<Pathname> {
    pathname: Pathname;
    query?: Query | undefined;
    hash?: string | null | undefined;
  }

  interface DynamicRoute<Pathname, Parameters> {
    pathname: Pathname;
    query: Parameters & Query;
    hash?: string | null | undefined;
  }

  interface Query {
    [key: string]: string | string[] | undefined;
  };

  export type RoutedQuery<P extends Route["pathname"]> = Extract<
    Route,
    { pathname: P }
  >["query"];

  export type Locale = undefined;

  /**
   * A typesafe utility function for generating paths in your application.
   *
   * route({ pathname: "/foos/[foo]", query: { foo: "bar" }}) will produce "/foos/bar".
   */
  export declare function route(r: Route): string;
}
```

So it makes sense that the query would also possibly be `undefined`. However, this is not what's shown in the docs.

What would be the recommended way to solve this issue?

Pull request:
add GetServerSideProps types
fixes #126

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 885969d..35dba86 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,7 +3,8 @@
 ## 1.0.9
 
 - Enable `Link` and `router` methods to only update the route `hash`. Thanks @sitch!
-- Publish commonjs for `route` runtime so jest tests don't require transpilation for users. Thanks @panudetjt.
+- Publish commonjs for `route` runtime so jest tests don't require transpilation for users. Thanks @panudetjt!
+- Add `GetServerSidePropsContext` type. Thanks @slhck!
 
 ## 1.0.8
 
diff --git a/README.md b/README.md
index 28e3410..5a807ca 100644
--- a/README.md
+++ b/README.md
@@ -147,6 +147,15 @@ If you want to use the generated `Route` type in your code, you can import it fr
 import type { Route } from "nextjs-routes";
 ```
 
+### Pathname
+
+If you want a type for all possible `pathname`s you can achieve this via `Route`:
+
+```ts
+import type { Route } from "nextjs-routes";
+type Pathname = Route["pathname"];
+```
+
 ### RoutedQuery
 
 If you want to use the generated `Query` for a given `Route`, you can import it from `nextjs-routes`:
@@ -155,18 +164,32 @@ If you want to use the generated `Query` for a given `Route`, you can import it
 import type { RoutedQuery } from "nextjs-routes";
 ```
 
-This is useful as the context type parameter inside `getStaticProps` and `getServerSideProps`:
+### GetServerSidePropsContext
+
+If you're using `getServerSideProps` consider using `GetServerSidePropsContext` from nextjs-routes. This is nearly identical to `GetServerSidePropsContext` from next, but further narrows types based on nextjs-route's route data.
 
 ```ts
-import type { GetStaticProps } from "next";
-import type { RoutedQuery } from "nextjs-routes";
+import type { GetServerSidePropsContext } from "nextjs-routes";
 
-export const getStaticProps: GetStaticProps<{}, RoutedQuery<"/foos/[foo]">> = (
-  context
-) => {
-  // context.params will include `foo` as a string
+export function getServerSideProps(
+  context: GetServerSidePropsContext<"/foos/[foo]">
+) {
+  // context.params will include `foo` as a string;
   const { foo } = context.params;
-};
+}
+```
+
+### GetServerSideProps
+
+If you're using `getServerSideProps` and TypeScript 4.9 or later, you can combine the [satisfies](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-9.html#the-satisfies-operator) operator with `GetServerSideProps` from nextjs-routes. This is nearly identical to `GetServerSideProps` from next, but further narrows types based on nextjs-route's route data.
+
+```ts
+import type { GetServerSideProps } from "nextjs-routes";
+
+export const getServerSideProps = (async (context) => {
+  // context.params will include `foo` as a string;
+  const { foo } = context.params;
+}) satisfies GetServerSideProps<{}, "/foos/[foo]">;
 ```
 
 ## How does this work? 🤔
@@ -190,16 +213,16 @@ fetch(route({ pathname: "/api/foos/[foo]", query: { foo: "foobar" } }));
 ### getServerSideProps
 
 ```ts
-import { route } from "nextjs-routes";
+import { route, type GetServerSidePropsContext } from "nextjs-routes";
 
-export const getServerSideProps: GetServerSideProps = async (context) => {
+export function getServerSideProps(context: GetServerSidePropsContext) {
   return {
     redirect: {
       destination: route({ pathname: "/foos/[foo]", query: { foo: "foobar" } }),
       permanent: false,
     },
   };
-};
+}
 ```
 
 ### Internationalization (i18n)
diff --git a/examples/app/nextjs-routes.d.ts b/examples/app/nextjs-routes.d.ts
index 3dff60b..dc8560e 100644
--- a/examples/app/nextjs-routes.d.ts
+++ b/examples/app/nextjs-routes.d.ts
@@ -5,6 +5,11 @@
 
 // prettier-ignore
 declare module "nextjs-routes" {
+  import type {
+    GetServerSidePropsContext as NextGetServerSidePropsContext,
+    GetServerSidePropsResult as NextGetServerSidePropsResult
+  } from "nextjs";
+
   export type Route =
     | DynamicRoute<"/[store]", { "store": string }>
     | StaticRoute<"/">;
@@ -38,6 +43,33 @@ declare module "nextjs-routes" {
    * route({ pathname: "/foos/[foo]", query: { foo: "bar" }}) will produce "/foos/bar".
    */
   export declare function route(r: Route): string;
+
+  /**
+   * Nearly identical to GetServerSidePropsContext from next, but further narrows
+   * types based on nextjs-route's route data.
+   */
+  export type GetServerSidePropsContext<
+    Pathname extends Route["pathname"] = Route["pathname"],
+    Preview extends NextGetServerSidePropsContext["previewData"] = NextGetServerSidePropsContext["previewData"]
+  > = Omit<NextGetServerSidePropsContext, 'params' | 'query' | 'defaultLocale' | 'locale' | 'locales'> & {
+    params: Extract<Route, { pathname: Pathname }>["query"];
+    query: Query;
+    defaultLocale?: undefined;
+    locale?: Locale;
+    locales?: undefined;
+  };
+
+  /**
+   * Nearly identical to GetServerSideProps from next, but further narrows
+   * types based on nextjs-route's route data.
+   */
+  export type GetServerSideProps<
+    Props extends { [key: string]: any } = { [key: string]: any },
+    Pathname extends Route["pathname"] = Route["pathname"],
+    Preview extends NextGetServerSideProps["previewData"] = NextGetServerSideProps["previewData"]
+  > = (
+    context: GetServerSidePropsContext<Pathname, Preview>
+  ) => Promise<NextGetServerSidePropsResult<Props>>
 }
 
 // prettier-ignore
diff --git a/examples/intl/nextjs-routes.d.ts b/examples/intl/nextjs-routes.d.ts
index 9520caf..27364ea 100644
--- a/examples/intl/nextjs-routes.d.ts
+++ b/examples/intl/nextjs-routes.d.ts
@@ -5,6 +5,11 @@
 
 // prettier-ignore
 declare module "nextjs-routes" {
+  import type {
+    GetServerSidePropsContext as NextGetServerSidePropsContext,
+    GetServerSidePropsResult as NextGetServerSidePropsResult
+  } from "nextjs";
+
   export type Route =
     | DynamicRoute<"/[store]", { "store": string }>
     | StaticRoute<"/">;
@@ -41,6 +46,37 @@ declare module "nextjs-routes" {
    * route({ pathname: "/foos/[foo]", query: { foo: "bar" }}) will produce "/foos/bar".
    */
   export declare function route(r: Route): string;
+
+  /**
+   * Nearly identical to GetServerSidePropsContext from next, but further narrows
+   * types based on nextjs-route's route data.
+   */
+  export type GetServerSidePropsContext<
+    Pathname extends Route["pathname"] = Route["pathname"],
+    Preview extends NextGetServerSidePropsContext["previewData"] = NextGetServerSidePropsContext["previewData"]
+  > = Omit<NextGetServerSidePropsContext, 'params' | 'query' | 'defaultLocale' | 'locale' | 'locales'> & {
+    params: Extract<Route, { pathname: Pathname }>["query"];
+    query: Query;
+    defaultLocale: "en-US";
+    locale: Locale;
+    locales: [
+          "en-US",
+          "fr",
+          "nl-NL"
+        ];
+  };
+
+  /**
+   * Nearly identical to GetServerSideProps from next, but further narrows
+   * types based on nextjs-route's route data.
+   */
+  export type GetServerSideProps<
+    Props extends { [key: string]: any } = { [key: string]: any },
+    Pathname extends Route["pathname"] = Route["pathname"],
+    Preview extends NextGetServerSideProps["previewData"] = NextGetServerSideProps["previewData"]
+  > = (
+    context: GetServerSidePropsContext<Pathname, Preview>
+  ) => Promise<NextGetServerSidePropsResult<Props>>
 }
 
 // prettier-ignore
diff --git a/examples/typescript/pages/foos/[foo].tsx b/examples/typescript/pages/foos/[foo].tsx
index 9798825..3437a43 100644
--- a/examples/typescript/pages/foos/[foo].tsx
+++ b/examples/typescript/pages/foos/[foo].tsx
@@ -1,6 +1,10 @@
-import { GetServerSideProps, NextPage } from "next";
+import { NextPage } from "next";
 import { useRouter } from "next/router";
-import { route } from "nextjs-routes";
+import {
+  route,
+  type GetServerSidePropsContext,
+  type GetServerSideProps,
+} from "nextjs-routes";
 
 const Foo: NextPage = () => {
   const router = useRouter<"/foos/[foo]">();
@@ -8,13 +12,18 @@ const Foo: NextPage = () => {
   return <div>Foo: {foo}</div>;
 };
 
-export const getServerSideProps: GetServerSideProps = async () => {
+export const getServerSideProps = (async (
+  ctx: GetServerSidePropsContext<"/foos/[foo]">
+) => {
   return {
     redirect: {
-      destination: route({ pathname: "/bars/[bar]", query: { bar: "foo" } }),
+      destination: route({
+        pathname: "/bars/[bar]",
+        query: { bar: ctx.params.foo },
+      }),
       permanent: false,
     },
   };
-};
+}) satisfies GetServerSideProps<{}, "/foos/[foo]">;
 
 export default Foo;
diff --git a/examples/typescript/types/nextjs-routes.d.ts b/examples/typescript/types/nextjs-routes.d.ts
index ad1e2a8..14eb6a2 100644
--- a/examples/typescript/types/nextjs-routes.d.ts
+++ b/examples/typescript/types/nextjs-routes.d.ts
@@ -5,6 +5,11 @@
 
 // prettier-ignore
 declare module "nextjs-routes" {
+  import type {
+    GetServerSidePropsContext as NextGetServerSidePropsContext,
+    GetServerSidePropsResult as NextGetServerSidePropsResult
+  } from "nextjs";
+
   export type Route =
     | StaticRoute<"/api/hello">
     | DynamicRoute<"/bars/[bar]", { "bar": string }>
@@ -40,6 +45,33 @@ declare module "nextjs-routes" {
    * route({ pathname: "/foos/[foo]", query: { foo: "bar" }}) will produce "/foos/bar".
    */
   export declare function route(r: Route): string;
+
+  /**
+   * Nearly identical to GetServerSidePropsContext from next, but further narrows
+   * types based on nextjs-route's route data.
+   */
+  export type GetServerSidePropsContext<
+    Pathname extends Route["pathname"] = Route["pathname"],
+    Preview extends NextGetServerSidePropsContext["previewData"] = NextGetServerSidePropsContext["previewData"]
+  > = Omit<NextGetServerSidePropsContext, 'params' | 'query' | 'defaultLocale' | 'locale' | 'locales'> & {
+    params: Extract<Route, { pathname: Pathname }>["query"];
+    query: Query;
+    defaultLocale?: undefined;
+    locale?: Locale;
+    locales?: undefined;
+  };
+
+  /**
+   * Nearly identical to GetServerSideProps from next, but further narrows
+   * types based on nextjs-route's route data.
+   */
+  export type GetServerSideProps<
+    Props extends { [key: string]: any } = { [key: string]: any },
+    Pathname extends Route["pathname"] = Route["pathname"],
+    Preview extends NextGetServerSideProps["previewData"] = NextGetServerSideProps["previewData"]
+  > = (
+    context: GetServerSidePropsContext<Pathname, Preview>
+  ) => Promise<NextGetServerSidePropsResult<Props>>
 }
 
 // prettier-ignore
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 36f6296..c5bdb04 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -68,12 +68,12 @@ importers:
       react-dom: '*'
       typescript: '*'
     dependencies:
-      next: 13.1.1_biqbaboplfbrettd7655fr4n2y
+      next: 13.2.4_biqbaboplfbrettd7655fr4n2y
       react: 18.2.0
       react-dom: 18.2.0_react@18.2.0
     devDependencies:
       nextjs-routes: link:../dist
-      typescript: 4.9.4
+      typescript: 5.0.3
 
   examples/app:
     specifiers:
@@ -7029,12 +7029,6 @@ packages:
     hasBin: true
     dev: true
 
-  /typescript/4.9.4:
-    resolution: {integrity: sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==}
-    engines: {node: '>=4.2.0'}
-    hasBin: true
-    dev: true
-
   /typescript/5.0.3:
     resolution: {integrity: sha512-xv8mOEDnigb/tN9PSMTwSEqAnUvkoXMQlicOb0IUVDBSQCgBSaAAROUZYy2IcUy5qU6XajK5jjjO7TMWqBTKZA==}
     engines: {node: '>=12.20'}
diff --git a/src/core.ts b/src/core.ts
index 2128b22..7d9a602 100644
--- a/src/core.ts
+++ b/src/core.ts
@@ -93,6 +93,11 @@ function generate(routes: Route[], config: NextJSRoutesOptions): string {
 
 // prettier-ignore
 declare module "nextjs-routes" {
+  import type {
+    GetServerSidePropsContext as NextGetServerSidePropsContext,
+    GetServerSidePropsResult as NextGetServerSidePropsResult
+  } from "nextjs";
+
   export type Route =
     ${
       !routes.length
@@ -140,6 +145,37 @@ declare module "nextjs-routes" {
    * route({ pathname: "/foos/[foo]", query: { foo: "bar" }}) will produce "/foos/bar".
    */
   export declare function route(r: Route): string;
+
+  /**
+   * Nearly identical to GetServerSidePropsContext from next, but further narrows
+   * types based on nextjs-route's route data.
+   */
+  export type GetServerSidePropsContext<
+    Pathname extends Route["pathname"] = Route["pathname"],
+    Preview extends NextGetServerSidePropsContext["previewData"] = NextGetServerSidePropsContext["previewData"]
+  > = Omit<NextGetServerSidePropsContext, 'params' | 'query' | 'defaultLocale' | 'locale' | 'locales'> & {
+    params: Extract<Route, { pathname: Pathname }>["query"];
+    query: Query;
+    defaultLocale${
+      i18n.defaultLocale ? `: "${i18n.defaultLocale}"` : "?: undefined"
+    };
+    locale${!i18n.locales.length ? "?:" : ":"} Locale;
+    locales${
+      i18n.locales.length ? `: ${print(i18n.locales, 8)}` : "?: undefined"
+    };
+  };
+
+  /**
+   * Nearly identical to GetServerSideProps from next, but further narrows
+   * types based on nextjs-route's route data.
+   */
+  export type GetServerSideProps<
+    Props extends { [key: string]: any } = { [key: string]: any },
+    Pathname extends Route["pathname"] = Route["pathname"],
+    Preview extends NextGetServerSideProps["previewData"] = NextGetServerSideProps["previewData"]
+  > = (
+    context: GetServerSidePropsContext<Pathname, Preview>
+  ) => Promise<NextGetServerSidePropsResult<Props>>
 }
 
 // prettier-ignore


Test patch:
diff --git a/e2e/nextjs-routes.d.ts b/e2e/nextjs-routes.d.ts
index 096aa06..fb44057 100644
--- a/e2e/nextjs-routes.d.ts
+++ b/e2e/nextjs-routes.d.ts
@@ -5,6 +5,11 @@
 
 // prettier-ignore
 declare module "nextjs-routes" {
+  import type {
+    GetServerSidePropsContext as NextGetServerSidePropsContext,
+    GetServerSidePropsResult as NextGetServerSidePropsResult
+  } from "nextjs";
+
   export type Route =
     | DynamicRoute<"/[...slug]", { "slug": string[] }>
     | DynamicRoute<"/foos/[foo]", { "foo": string }>
@@ -39,6 +44,33 @@ declare module "nextjs-routes" {
    * route({ pathname: "/foos/[foo]", query: { foo: "bar" }}) will produce "/foos/bar".
    */
   export declare function route(r: Route): string;
+
+  /**
+   * Nearly identical to GetServerSidePropsContext from next, but further narrows
+   * types based on nextjs-route's route data.
+   */
+  export type GetServerSidePropsContext<
+    Pathname extends Route["pathname"] = Route["pathname"],
+    Preview extends NextGetServerSidePropsContext["previewData"] = NextGetServerSidePropsContext["previewData"]
+  > = Omit<NextGetServerSidePropsContext, 'params' | 'query' | 'defaultLocale' | 'locale' | 'locales'> & {
+    params: Extract<Route, { pathname: Pathname }>["query"];
+    query: Query;
+    defaultLocale?: undefined;
+    locale?: Locale;
+    locales?: undefined;
+  };
+
+  /**
+   * Nearly identical to GetServerSideProps from next, but further narrows
+   * types based on nextjs-route's route data.
+   */
+  export type GetServerSideProps<
+    Props extends { [key: string]: any } = { [key: string]: any },
+    Pathname extends Route["pathname"] = Route["pathname"],
+    Preview extends NextGetServerSideProps["previewData"] = NextGetServerSideProps["previewData"]
+  > = (
+    context: GetServerSidePropsContext<Pathname, Preview>
+  ) => Promise<NextGetServerSidePropsResult<Props>>
 }
 
 // prettier-ignore
diff --git a/e2e/typetest.tsx b/e2e/typetest.tsx
index 4627b8d..69d6655 100644
--- a/e2e/typetest.tsx
+++ b/e2e/typetest.tsx
@@ -1,7 +1,13 @@
 import Link from "next/link";
 import { LinkProps } from "next/link";
 import { useRouter, RouterEvent, NextRouter } from "next/router";
-import { route, type Route, type RoutedQuery } from "nextjs-routes";
+import {
+  route,
+  type Route,
+  type RoutedQuery,
+  type GetServerSideProps,
+  type GetServerSidePropsContext,
+} from "nextjs-routes";
 import withRoutes from "nextjs-routes/config";
 
 withRoutes();
@@ -270,3 +276,37 @@ rq2 = { foo: "bar" };
 rq2 = { bar: "baz" };
 // @ts-expect-error 'foo' must be a string, not string[]
 rq2 = { foo: ["bar", "baz"] };
+
+let getServerSideProps = (async (
+  ctx: GetServerSidePropsContext<"/foos/[foo]">
+) => {
+  expectType<string>(ctx.params.foo);
+  return {
+    redirect: {
+      destination: route({
+        pathname: "/foos/[foo]",
+        query: { foo: ctx.params.foo },
+      }),
+      permanent: false,
+    },
+  };
+}) satisfies GetServerSideProps<{}, "/foos/[foo]">;
+
+expectType<
+  (
+    ctx: GetServerSidePropsContext<"/foos/[foo]">
+  ) => Promise<{ redirect: { destination: string; permanent: boolean } }>
+>(getServerSideProps);
+
+getServerSideProps = (async (ctx) => {
+  expectType<string>(ctx.params.foo);
+  return {
+    redirect: {
+      destination: route({
+        pathname: "/foos/[foo]",
+        query: { foo: ctx.params.foo },
+      }),
+      permanent: false,
+    },
+  };
+}) satisfies GetServerSideProps<{}, "/foos/[foo]">;
diff --git a/src/__snapshots__/core.test.ts.snap b/src/__snapshots__/core.test.ts.snap
index 8ed1382..42fe9c1 100644
--- a/src/__snapshots__/core.test.ts.snap
+++ b/src/__snapshots__/core.test.ts.snap
@@ -11,6 +11,11 @@ exports[`route generation app directory (experimental) 1`] = `
 
 // prettier-ignore
 declare module "nextjs-routes" {
+  import type {
+    GetServerSidePropsContext as NextGetServerSidePropsContext,
+    GetServerSidePropsResult as NextGetServerSidePropsResult
+  } from "nextjs";
+
   export type Route =
     | StaticRoute<"/">
     | StaticRoute<"/foo">
@@ -45,6 +50,33 @@ declare module "nextjs-routes" {
    * route({ pathname: "/foos/[foo]", query: { foo: "bar" }}) will produce "/foos/bar".
    */
   export declare function route(r: Route): string;
+
+  /**
+   * Nearly identical to GetServerSidePropsContext from next, but further narrows
+   * types based on nextjs-route's route data.
+   */
+  export type GetServerSidePropsContext<
+    Pathname extends Route["pathname"] = Route["pathname"],
+    Preview extends NextGetServerSidePropsContext["previewData"] = NextGetServerSidePropsContext["previewData"]
+  > = Omit<NextGetServerSidePropsContext, 'params' | 'query' | 'defaultLocale' | 'locale' | 'locales'> & {
+    params: Extract<Route, { pathname: Pathname }>["query"];
+    query: Query;
+    defaultLocale?: undefined;
+    locale?: Locale;
+    locales?: undefined;
+  };
+
+  /**
+   * Nearly identical to GetServerSideProps from next, but further narrows
+   * types based on nextjs-route's route data.
+   */
+  export type GetServerSideProps<
+    Props extends { [key: string]: any } = { [key: string]: any },
+    Pathname extends Route["pathname"] = Route["pathname"],
+    Preview extends NextGetServerSideProps["previewData"] = NextGetServerSideProps["previewData"]
+  > = (
+    context: GetServerSidePropsContext<Pathname, Preview>
+  ) => Promise<NextGetServerSidePropsResult<Props>>
 }
 
 // prettier-ignore
@@ -143,6 +175,11 @@ exports[`route generation configuration i18n 1`] = `
 
 // prettier-ignore
 declare module "nextjs-routes" {
+  import type {
+    GetServerSidePropsContext as NextGetServerSidePropsContext,
+    GetServerSidePropsResult as NextGetServerSidePropsResult
+  } from "nextjs";
+
   export type Route =
     | StaticRoute<"/">;
 
@@ -178,6 +215,37 @@ declare module "nextjs-routes" {
    * route({ pathname: "/foos/[foo]", query: { foo: "bar" }}) will produce "/foos/bar".
    */
   export declare function route(r: Route): string;
+
+  /**
+   * Nearly identical to GetServerSidePropsContext from next, but further narrows
+   * types based on nextjs-route's route data.
+   */
+  export type GetServerSidePropsContext<
+    Pathname extends Route["pathname"] = Route["pathname"],
+    Preview extends NextGetServerSidePropsContext["previewData"] = NextGetServerSidePropsContext["previewData"]
+  > = Omit<NextGetServerSidePropsContext, 'params' | 'query' | 'defaultLocale' | 'locale' | 'locales'> & {
+    params: Extract<Route, { pathname: Pathname }>["query"];
+    query: Query;
+    defaultLocale: "en-US";
+    locale: Locale;
+    locales: [
+          "en-US",
+          "fr",
+          "nl-NL"
+        ];
+  };
+
+  /**
+   * Nearly identical to GetServerSideProps from next, but further narrows
+   * types based on nextjs-route's route data.
+   */
+  export type GetServerSideProps<
+    Props extends { [key: string]: any } = { [key: string]: any },
+    Pathname extends Route["pathname"] = Route["pathname"],
+    Preview extends NextGetServerSideProps["previewData"] = NextGetServerSideProps["previewData"]
+  > = (
+    context: GetServerSidePropsContext<Pathname, Preview>
+  ) => Promise<NextGetServerSidePropsResult<Props>>
 }
 
 // prettier-ignore
@@ -293,6 +361,11 @@ exports[`route generation configuration outDir 1`] = `
 
 // prettier-ignore
 declare module "nextjs-routes" {
+  import type {
+    GetServerSidePropsContext as NextGetServerSidePropsContext,
+    GetServerSidePropsResult as NextGetServerSidePropsResult
+  } from "nextjs";
+
   export type Route =
     | StaticRoute<"/404">;
 
@@ -325,6 +398,33 @@ declare module "nextjs-routes" {
    * route({ pathname: "/foos/[foo]", query: { foo: "bar" }}) will produce "/foos/bar".
    */
   export declare function route(r: Route): string;
+
+  /**
+   * Nearly identical to GetServerSidePropsContext from next, but further narrows
+   * types based on nextjs-route's route data.
+   */
+  export type GetServerSidePropsContext<
+    Pathname extends Route["pathname"] = Route["pathname"],
+    Preview extends NextGetServerSidePropsContext["previewData"] = NextGetServerSidePropsContext["previewData"]
+  > = Omit<NextGetServerSidePropsContext, 'params' | 'query' | 'defaultLocale' | 'locale' | 'locales'> & {
+    params: Extract<Route, { pathname: Pathname }>["query"];
+    query: Query;
+    defaultLocale?: undefined;
+    locale?: Locale;
+    locales?: undefined;
+  };
+
+  /**
+   * Nearly identical to GetServerSideProps from next, but further narrows
+   * types based on nextjs-route's route data.
+   */
+  export type GetServerSideProps<
+    Props extends { [key: string]: any } = { [key: string]: any },
+    Pathname extends Route["pathname"] = Route["pathname"],
+    Preview extends NextGetServerSideProps["previewData"] = NextGetServerSideProps["previewData"]
+  > = (
+    context: GetServerSidePropsContext<Pathname, Preview>
+  ) => Promise<NextGetServerSidePropsResult<Props>>
 }
 
 // prettier-ignore
@@ -423,6 +523,11 @@ exports[`route generation configuration pageExtensions configured 1`] = `
 
 // prettier-ignore
 declare module "nextjs-routes" {
+  import type {
+    GetServerSidePropsContext as NextGetServerSidePropsContext,
+    GetServerSidePropsResult as NextGetServerSidePropsResult
+  } from "nextjs";
+
   export type Route =
     | StaticRoute<"/404">
     | StaticRoute<"/">
@@ -457,6 +562,33 @@ declare module "nextjs-routes" {
    * route({ pathname: "/foos/[foo]", query: { foo: "bar" }}) will produce "/foos/bar".
    */
   export declare function route(r: Route): string;
+
+  /**
+   * Nearly identical to GetServerSidePropsContext from next, but further narrows
+   * types based on nextjs-route's route data.
+   */
+  export type GetServerSidePropsContext<
+    Pathname extends Route["pathname"] = Route["pathname"],
+    Preview extends NextGetServerSidePropsContext["previewData"] = NextGetServerSidePropsContext["previewData"]
+  > = Omit<NextGetServerSidePropsContext, 'params' | 'query' | 'defaultLocale' | 'locale' | 'locales'> & {
+    params: Extract<Route, { pathname: Pathname }>["query"];
+    query: Query;
+    defaultLocale?: undefined;
+    locale?: Locale;
+    locales?: undefined;
+  };
+
+  /**
+   * Nearly identical to GetServerSideProps from next, but further narrows
+   * types based on nextjs-route's route data.
+   */
+  export type GetServerSideProps<
+    Props extends { [key: string]: any } = { [key: string]: any },
+    Pathname extends Route["pathname"] = Route["pathname"],
+    Preview extends NextGetServerSideProps["previewData"] = NextGetServerSideProps["previewData"]
+  > = (
+    context: GetServerSidePropsContext<Pathname, Preview>
+  ) => Promise<NextGetServerSidePropsResult<Props>>
 }
 
 // prettier-ignore
@@ -555,6 +687,11 @@ exports[`route generation configuration pageExtensions default 1`] = `
 
 // prettier-ignore
 declare module "nextjs-routes" {
+  import type {
+    GetServerSidePropsContext as NextGetServerSidePropsContext,
+    GetServerSidePropsResult as NextGetServerSidePropsResult
+  } from "nextjs";
+
   export type Route =
     | StaticRoute<"/404">;
 
@@ -587,6 +724,33 @@ declare module "nextjs-routes" {
    * route({ pathname: "/foos/[foo]", query: { foo: "bar" }}) will produce "/foos/bar".
    */
   export declare function route(r: Route): string;
+
+  /**
+   * Nearly identical to GetServerSidePropsContext from next, but further narrows
+   * types based on nextjs-route's route data.
+   */
+  export type GetServerSidePropsContext<
+    Pathname extends Route["pathname"] = Route["pathname"],
+    Preview extends NextGetServerSidePropsContext["previewData"] = NextGetServerSidePropsContext["previewData"]
+  > = Omit<NextGetServerSidePropsContext, 'params' | 'query' | 'defaultLocale' | 'locale' | 'locales'> & {
+    params: Extract<Route, { pathname: Pathname }>["query"];
+    query: Query;
+    defaultLocale?: undefined;
+    locale?: Locale;
+    locales?: undefined;
+  };
+
+  /**
+   * Nearly identical to GetServerSideProps from next, but further narrows
+   * types based on nextjs-route's route data.
+   */
+  export type GetServerSideProps<
+    Props extends { [key: string]: any } = { [key: string]: any },
+    Pathname extends Route["pathname"] = Route["pathname"],
+    Preview extends NextGetServerSideProps["previewData"] = NextGetServerSideProps["previewData"]
+  > = (
+    context: GetServerSidePropsContext<Pathname, Preview>
+  ) => Promise<NextGetServerSidePropsResult<Props>>
 }
 
 // prettier-ignore
@@ -685,6 +849,11 @@ exports[`route generation dedupes 1`] = `
 
 // prettier-ignore
 declare module "nextjs-routes" {
+  import type {
+    GetServerSidePropsContext as NextGetServerSidePropsContext,
+    GetServerSidePropsResult as NextGetServerSidePropsResult
+  } from "nextjs";
+
   export type Route =
     | StaticRoute<"/">;
 
@@ -717,6 +886,33 @@ declare module "nextjs-routes" {
    * route({ pathname: "/foos/[foo]", query: { foo: "bar" }}) will produce "/foos/bar".
    */
   export declare function route(r: Route): string;
+
+  /**
+   * Nearly identical to GetServerSidePropsContext from next, but further narrows
+   * types based on nextjs-route's route data.
+   */
+  export type GetServerSidePropsContext<
+    Pathname extends Route["pathname"] = Route["pathname"],
+    Preview extends NextGetServerSidePropsContext["previewData"] = NextGetServerSidePropsContext["previewData"]
+  > = Omit<NextGetServerSidePropsContext, 'params' | 'query' | 'defaultLocale' | 'locale' | 'locales'> & {
+    params: Extract<Route, { pathname: Pathname }>["query"];
+    query: Query;
+    defaultLocale?: undefined;
+    locale?: Locale;
+    locales?: undefined;
+  };
+
+  /**
+   * Nearly identical to GetServerSideProps from next, but further narrows
+   * types based on nextjs-route's route data.
+   */
+  export type GetServerSideProps<
+    Props extends { [key: string]: any } = { [key: string]: any },
+    Pathname extends Route["pathname"] = Route["pathname"],
+    Preview extends NextGetServerSideProps["previewData"] = NextGetServerSideProps["previewData"]
+  > = (
+    context: GetServerSidePropsContext<Pathname, Preview>
+  ) => Promise<NextGetServerSidePropsResult<Props>>
 }
 
 // prettier-ignore
@@ -815,6 +1011,11 @@ exports[`route generation no routes 1`] = `
 
 // prettier-ignore
 declare module "nextjs-routes" {
+  import type {
+    GetServerSidePropsContext as NextGetServerSidePropsContext,
+    GetServerSidePropsResult as NextGetServerSidePropsResult
+  } from "nextjs";
+
   export type Route =
     never;
 
@@ -847,6 +1048,33 @@ declare module "nextjs-routes" {
    * route({ pathname: "/foos/[foo]", query: { foo: "bar" }}) will produce "/foos/bar".
    */
   export declare function route(r: Route): string;
+
+  /**
+   * Nearly identical to GetServerSidePropsContext from next, but further narrows
+   * types based on nextjs-route's route data.
+   */
+  export type GetServerSidePropsContext<
+    Pathname extends Route["pathname"] = Route["pathname"],
+    Preview extends NextGetServerSidePropsContext["previewData"] = NextGetServerSidePropsContext["previewData"]
+  > = Omit<NextGetServerSidePropsContext, 'params' | 'query' | 'defaultLocale' | 'locale' | 'locales'> & {
+    params: Extract<Route, { pathname: Pathname }>["query"];
+    query: Query;
+    defaultLocale?: undefined;
+    locale?: Locale;
+    locales?: undefined;
+  };
+
+  /**
+   * Nearly identical to GetServerSideProps from next, but further narrows
+   * types based on nextjs-route's route data.
+   */
+  export type GetServerSideProps<
+    Props extends { [key: string]: any } = { [key: string]: any },
+    Pathname extends Route["pathname"] = Route["pathname"],
+    Preview extends NextGetServerSideProps["previewData"] = NextGetServerSideProps["previewData"]
+  > = (
+    context: GetServerSidePropsContext<Pathname, Preview>
+  ) => Promise<NextGetServerSidePropsResult<Props>>
 }
 
 // prettier-ignore
@@ -945,6 +1173,11 @@ exports[`route generation transforms windows paths 1`] = `
 
 // prettier-ignore
 declare module "nextjs-routes" {
+  import type {
+    GetServerSidePropsContext as NextGetServerSidePropsContext,
+    GetServerSidePropsResult as NextGetServerSidePropsResult
+  } from "nextjs";
+
   export type Route =
     | DynamicRoute<"src/pages/[foo]/bar", { "foo": string }>;
 
@@ -977,6 +1210,33 @@ declare module "nextjs-routes" {
    * route({ pathname: "/foos/[foo]", query: { foo: "bar" }}) will produce "/foos/bar".
    */
   export declare function route(r: Route): string;
+
+  /**
+   * Nearly identical to GetServerSidePropsContext from next, but further narrows
+   * types based on nextjs-route's route data.
+   */
+  export type GetServerSidePropsContext<
+    Pathname extends Route["pathname"] = Route["pathname"],
+    Preview extends NextGetServerSidePropsContext["previewData"] = NextGetServerSidePropsContext["previewData"]
+  > = Omit<NextGetServerSidePropsContext, 'params' | 'query' | 'defaultLocale' | 'locale' | 'locales'> & {
+    params: Extract<Route, { pathname: Pathname }>["query"];
+    query: Query;
+    defaultLocale?: undefined;
+    locale?: Locale;
+    locales?: undefined;
+  };
+
+  /**
+   * Nearly identical to GetServerSideProps from next, but further narrows
+   * types based on nextjs-route's route data.
+   */
+  export type GetServerSideProps<
+    Props extends { [key: string]: any } = { [key: string]: any },
+    Pathname extends Route["pathname"] = Route["pathname"],
+    Preview extends NextGetServerSideProps["previewData"] = NextGetServerSideProps["previewData"]
+  > = (
+    context: GetServerSidePropsContext<Pathname, Preview>
+  ) => Promise<NextGetServerSidePropsResult<Props>>
 }
 
 // prettier-ignore
@@ -1075,6 +1335,11 @@ exports[`route generation typescript 1`] = `
 
 // prettier-ignore
 declare module "nextjs-routes" {
+  import type {
+    GetServerSidePropsContext as NextGetServerSidePropsContext,
+    GetServerSidePropsResult as NextGetServerSidePropsResult
+  } from "nextjs";
+
   export type Route =
     | StaticRoute<"/404">
     | DynamicRoute<"/[foo]", { "foo": string }>
@@ -1124,6 +1389,33 @@ declare module "nextjs-routes" {
    * route({ pathname: "/foos/[foo]", query: { foo: "bar" }}) will produce "/foos/bar".
    */
   export declare function route(r: Route): string;
+
+  /**
+   * Nearly identical to GetServerSidePropsContext from next, but further narrows
+   * types based on nextjs-route's route data.
+   */
+  export type GetServerSidePropsContext<
+    Pathname extends Route["pathname"] = Route["pathname"],
+    Preview extends NextGetServerSidePropsContext["previewData"] = NextGetServerSidePropsContext["previewData"]
+  > = Omit<NextGetServerSidePropsContext, 'params' | 'query' | 'defaultLocale' | 'locale' | 'locales'> & {
+    params: Extract<Route, { pathname: Pathname }>["query"];
+    query: Query;
+    defaultLocale?: undefined;
+    locale?: Locale;
+    locales?: undefined;
+  };
+
+  /**
+   * Nearly identical to GetServerSideProps from next, but further narrows
+   * types based on nextjs-route's route data.
+   */
+  export type GetServerSideProps<
+    Props extends { [key: string]: any } = { [key: string]: any },
+    Pathname extends Route["pathname"] = Route["pathname"],
+    Preview extends NextGetServerSideProps["previewData"] = NextGetServerSideProps["previewData"]
+  > = (
+    context: GetServerSidePropsContext<Pathname, Preview>
+  ) => Promise<NextGetServerSidePropsResult<Props>>
 }
 
 // prettier-ignore