Repository: TanStack/router
Pull request #2258 (2024-09-03 21:08:21)

feat: pass `matches` into `context()` and `beforeLoad()`
this will allow typesafe access to the matches so something like this can be done:

```tsx
  beforeLoad: (c) => {
    const leafMatch = c.matches[c.matches.length - 1];
    if (leafMatch.fullPath === '/dashboard/invoices/$invoiceId') {
      if (leafMatch.params.invoiceId === '1') {
         // do something
      }
    }
```

nx-cloud[bot]: # ☁️ Nx Cloud Report

We didn't find any information for the current pull request with the commit 29a94c04eb634b8f2ad742a05cc00d693ede123f.
Please verify you are running the latest version of the [NxCloud runner](https://www.npmjs.com/package/nx-cloud).

Check [the Nx Cloud Source Control Integration documentation](https://nx.dev/nx-cloud/recipes/source-control-integration?utm_source=pull-request&utm_medium=comment) for more information.

Alternatively, you can contact us at [cloud-support@nrwl.io](mailto:cloud-support@nrwl.io).

---

Sent with 💌 from [NxCloud.](https://nx.app?utm_source=pull-request&utm_medium=comment)
pkg-pr-new[bot]: 
[Open in Stackblitz](https://pkg.pr.new/template/62d2d3ea-e79b-4d65-9d6b-b64b4f36bd4c)
<details><summary><b>More templates</b></summary><p>

- [tanstack-router-react-example-authenticated-routes](https://pkg.pr.new/template/f8a7c98e-e514-4bb7-a101-5a37f99ca529)
- [tanstack-router-react-example-basic](https://pkg.pr.new/template/b8d6d5d7-1e0b-4d15-83be-dd49301f0508)
- [tanstack-router-react-example-basic-default-search-params](https://pkg.pr.new/template/97a5673a-ee91-42dc-b84d-954f27b09e07)
- [tanstack-router-react-example-basic-file-based](https://pkg.pr.new/template/b20587a1-3f79-400e-bc23-56e21161b866)
- [tanstack-router-react-example-basic-file-based-codesplitting](https://pkg.pr.new/template/ba0ff0be-e2ee-4424-a799-1f928b98fb91)
- [tanstack-router-react-example-react-query](https://pkg.pr.new/template/dac33b0f-9c84-45bb-8f23-c48098202d19)
- [tanstack-router-react-example-basic-react-query-file-based](https://pkg.pr.new/template/18c53dc5-bf75-4c9c-a77d-8effb3427350)
- [tanstack-router-react-example-basic-ssr-file-based](https://pkg.pr.new/template/80e77753-549f-44ba-9d36-6dce5fe9b1ed)
- [tanstack-router-react-example-basic-ssr-streaming-file-based](https://pkg.pr.new/template/d95c5313-6371-4d96-8a2c-4bceff6eebae)
- [tanstack-router-react-example-deferred-data](https://pkg.pr.new/template/9e7833bb-f98c-45ed-a0d4-459159974b74)
- [tanstack-router-react-example-kitchen-sink](https://pkg.pr.new/template/7949ef17-17b1-4c86-90f1-21cb071d3954)
- [tanstack-router-react-example-kitchen-sink-file-based](https://pkg.pr.new/template/b69fc3a1-08cf-4ac0-a0fe-fcac1d17430f)
- [tanstack-router-react-example-kitchen-sink-react-query](https://pkg.pr.new/template/656787bb-9bc4-46d6-a84e-6aeb1a7778b2)
- [tanstack-router-react-example-kitchen-sink-react-query-file-based](https://pkg.pr.new/template/d8ff47da-2d85-4d74-a2f6-1c4b60f5edd4)
- [tanstack-router-react-example-large-file-based](https://pkg.pr.new/template/c8d4ecbf-4de0-444d-90c5-f22fd2f24c8f)
- [tanstack-router-react-example-location-masking](https://pkg.pr.new/template/ea80c1c2-79f5-43ef-a29e-b5be7c646fa6)
- [tanstack-router-react-example-navigation-blocking](https://pkg.pr.new/template/ebce8892-d5d7-4d73-a564-5c36d2bc5d83)
- [tanstack-router-react-example-quickstart](https://pkg.pr.new/template/f8af8523-1a57-4642-8c64-18947c15e60a)
- [tanstack-router-react-example-quickstart-file-based](https://pkg.pr.new/template/5b3f8644-c91f-4ebe-b6cf-b38907138828)
- [tanstack-router-react-example-quickstart-rspack-file-based](https://pkg.pr.new/template/2df884d8-2422-4186-99bd-c4f0b9ce62f0)
- [tanstack-router-react-example-scroll-restoration](https://pkg.pr.new/template/4077c2cc-d8b9-400d-bce2-cadab01f2c1f)
- [tanstack-router-react-example-quickstart-webpack-file-based](https://pkg.pr.new/template/82616a22-19e3-46f9-a697-6720fc8887c0)
- [tanstack-router-search-validator-adapters](https://pkg.pr.new/template/00bea37e-3b94-4a43-a4ac-5fd17d081856)
- [tanstack-router-example-react-start-basic](https://pkg.pr.new/template/88bf522a-4aa7-4ee4-93c5-d2c059807deb)
- [tanstack-router-example-react-start-basic-auth](https://pkg.pr.new/template/ca8c17f1-2113-4cf5-8b49-c5741cbc2df2)
- [tanstack-router-example-react-start-basic-counter](https://pkg.pr.new/template/037d0293-dc37-46c1-a886-0865edd525fc)
- [tanstack-router-example-react-start-basic-react-query](https://pkg.pr.new/template/72f6b549-8a0a-4c04-aa4e-529b486f3dff)
- [tanstack-router-example-react-start-basic-rsc](https://pkg.pr.new/template/9c1b2d05-2c86-4809-bcf9-06559a2ba992)
- [tanstack-router-example-react-start-clerk-basic](https://pkg.pr.new/template/f18b4bca-f759-4bc9-b3ed-9628e0b1d1a0)
- [tanstack-router-example-react-start-trello-trellaux](https://pkg.pr.new/template/b2e1a788-d5b6-4113-a8a5-d8b30127be32)
- [tanstack-router-example-react-start-trellaux](https://pkg.pr.new/template/d8da6fc1-1aaf-4d22-841f-331b48e96cd6)
- [tanstack-router-react-example-with-framer-motion](https://pkg.pr.new/template/97af9fe5-379c-4253-a493-af868bc444bc)
- [tanstack-router-react-example-with-trpc](https://pkg.pr.new/template/cd0ea1af-b86a-48fa-8101-07ef45ff1b88)
- [tanstack-router-react-example-with-trpc-react-query](https://pkg.pr.new/template/4c012988-9ec3-46a4-be55-0792fd025f38)

</p></details>
      
    


<details><summary><b>@tanstack/react-cross-context</b></summary><p>

```
pnpm add https://pkg.pr.new/@tanstack/react-cross-context@2258
```

</p></details>
      
    

<details><summary><b>@tanstack/history</b></summary><p>

```
pnpm add https://pkg.pr.new/@tanstack/history@2258
```

</p></details>
      
    

<details><summary><b>@tanstack/react-router</b></summary><p>

```
pnpm add https://pkg.pr.new/@tanstack/react-router@2258
```

</p></details>
      
    

<details><summary><b>@tanstack/router-arktype-adapter</b></summary><p>

```
pnpm add https://pkg.pr.new/@tanstack/router-arktype-adapter@2258
```

</p></details>
      
    

<details><summary><b>@tanstack/react-router-with-query</b></summary><p>

```
pnpm add https://pkg.pr.new/@tanstack/react-router-with-query@2258
```

</p></details>
      
    

<details><summary><b>@tanstack/router-cli</b></summary><p>

```
pnpm add https://pkg.pr.new/@tanstack/router-cli@2258
```

</p></details>
      
    

<details><summary><b>@tanstack/router-generator</b></summary><p>

```
pnpm add https://pkg.pr.new/@tanstack/router-generator@2258
```

</p></details>
      
    

<details><summary><b>@tanstack/router-devtools</b></summary><p>

```
pnpm add https://pkg.pr.new/@tanstack/router-devtools@2258
```

</p></details>
      
    

<details><summary><b>@tanstack/router-plugin</b></summary><p>

```
pnpm add https://pkg.pr.new/@tanstack/router-plugin@2258
```

</p></details>
      
    

<details><summary><b>@tanstack/router-vite-plugin</b></summary><p>

```
pnpm add https://pkg.pr.new/@tanstack/router-vite-plugin@2258
```

</p></details>
      
    

<details><summary><b>@tanstack/router-valibot-adapter</b></summary><p>

```
pnpm add https://pkg.pr.new/@tanstack/router-valibot-adapter@2258
```

</p></details>
      
    

<details><summary><b>@tanstack/router-zod-adapter</b></summary><p>

```
pnpm add https://pkg.pr.new/@tanstack/router-zod-adapter@2258
```

</p></details>
      
    

<details><summary><b>@tanstack/start</b></summary><p>

```
pnpm add https://pkg.pr.new/@tanstack/start@2258
```

</p></details>
      
    

<details><summary><b>@tanstack/start-vite-plugin</b></summary><p>

```
pnpm add https://pkg.pr.new/@tanstack/start-vite-plugin@2258
```

</p></details>
      
    

_commit: <a href="https://github.com/TanStack/router/runs/29635591913"><code>29a94c0</code></a>_


Patch:
diff --git a/packages/react-router/src/Matches.tsx b/packages/react-router/src/Matches.tsx
index e6359a32b..fd58cab15 100644
--- a/packages/react-router/src/Matches.tsx
+++ b/packages/react-router/src/Matches.tsx
@@ -352,8 +352,8 @@ export function MatchRoute<
   return params ? props.children : null
 }
 
-export type MakeRouteMatches<
-  TRouter extends AnyRouter = AnyRouter,
+export type MakeRouteMatchUnion<
+  TRouter extends AnyRouter = RegisteredRouter,
   TRoute extends AnyRoute = ParseRoute<TRouter['routeTree']>,
 > = TRoute extends any
   ? RouteMatch<
@@ -369,7 +369,7 @@ export type MakeRouteMatches<
 
 export function useMatches<
   TRouter extends AnyRouter = RegisteredRouter,
-  TRouteMatch = MakeRouteMatches<TRouter>,
+  TRouteMatch = MakeRouteMatchUnion<TRouter>,
   T = Array<TRouteMatch>,
 >(opts?: { select?: (matches: Array<TRouteMatch>) => T }): T {
   return useRouterState({
diff --git a/packages/react-router/src/route.ts b/packages/react-router/src/route.ts
index 79d0cf3d3..6256d83d4 100644
--- a/packages/react-router/src/route.ts
+++ b/packages/react-router/src/route.ts
@@ -11,7 +11,7 @@ import { rootRouteId } from './root'
 import type * as React from 'react'
 import type { RootRouteId } from './root'
 import type { UseNavigateResult } from './useNavigate'
-import type { MakeRouteMatch, RouteMatch } from './Matches'
+import type { MakeRouteMatch, MakeRouteMatchUnion, RouteMatch } from './Matches'
 import type { NavigateOptions, ParsePathParams, ToMaskOptions } from './link'
 import type { ParsedLocation } from './location'
 import type { RouteById, RouteIds, RoutePaths } from './routeInfo'
@@ -285,6 +285,7 @@ export interface ContextOptions<
   navigate: NavigateFn
   buildLocation: BuildLocationFn
   cause: 'preload' | 'enter' | 'stay'
+  matches: Array<MakeRouteMatchUnion>
 }
 
 export interface RouteContextOptions<
diff --git a/packages/react-router/src/router.ts b/packages/react-router/src/router.ts
index 0de4f86f1..60821a02b 100644
--- a/packages/react-router/src/router.ts
+++ b/packages/react-router/src/router.ts
@@ -1264,6 +1264,7 @@ export class Router<
         cause: match.cause,
         abortController: match.abortController,
         preload: !!match.preload,
+        matches,
       }
 
       // Get the route context
@@ -2080,6 +2081,7 @@ export class Router<
                       this.navigate({ ...opts, _fromLocation: location }),
                     buildLocation: this.buildLocation,
                     cause: preload ? 'preload' : cause,
+                    matches,
                   }
 
                   let beforeLoadContext =


Test patch:
diff --git a/packages/react-router/tests/route.test-d.tsx b/packages/react-router/tests/route.test-d.tsx
index c005f052d..3fdfb5d2b 100644
--- a/packages/react-router/tests/route.test-d.tsx
+++ b/packages/react-router/tests/route.test-d.tsx
@@ -16,6 +16,7 @@ import type {
   Route,
   SearchSchemaInput,
 } from '../src'
+import type { MakeRouteMatchUnion } from '../src/Matches'
 
 test('when creating the root', () => {
   const rootRoute = createRootRoute()
@@ -38,6 +39,7 @@ test('when creating the root with routeContext', () => {
         cause: 'preload' | 'enter' | 'stay'
         context: {}
         search: {}
+        matches: Array<MakeRouteMatchUnion>
       }>()
     },
   })
@@ -60,6 +62,7 @@ test('when creating the root with beforeLoad', () => {
         cause: 'preload' | 'enter' | 'stay'
         context: {}
         search: {}
+        matches: Array<MakeRouteMatchUnion>
       }>()
     },
   })
@@ -107,6 +110,7 @@ test('when creating the root route with context and routeContext', () => {
         cause: 'preload' | 'enter' | 'stay'
         context: { userId: string }
         search: {}
+        matches: Array<MakeRouteMatchUnion>
       }>()
     },
   })
@@ -141,6 +145,7 @@ test('when creating the root route with context and beforeLoad', () => {
         cause: 'preload' | 'enter' | 'stay'
         context: { userId: string }
         search: {}
+        matches: Array<MakeRouteMatchUnion>
       }>()
     },
   })
@@ -210,6 +215,7 @@ test('when creating the root route with context, routeContext, beforeLoad and a
         cause: 'preload' | 'enter' | 'stay'
         context: { userId: string }
         search: {}
+        matches: Array<MakeRouteMatchUnion>
       }>()
 
       return {
@@ -227,6 +233,7 @@ test('when creating the root route with context, routeContext, beforeLoad and a
         cause: 'preload' | 'enter' | 'stay'
         context: { userId: string; env: 'env1' }
         search: {}
+        matches: Array<MakeRouteMatchUnion>
       }>()
       return { permission: 'view' as const }
     },
@@ -319,6 +326,7 @@ test('when creating a child route with routeContext from the root route with con
         cause: 'preload' | 'enter' | 'stay'
         context: { userId: string }
         search: {}
+        matches: Array<MakeRouteMatchUnion>
       }>()
 
       return {
@@ -345,6 +353,7 @@ test('when creating a child route with beforeLoad from the root route with conte
         cause: 'preload' | 'enter' | 'stay'
         context: { userId: string }
         search: {}
+        matches: Array<MakeRouteMatchUnion>
       }>()
     },
   })
@@ -614,6 +623,7 @@ test('when creating a child route with params, search with routeContext from the
         cause: 'preload' | 'enter' | 'stay'
         context: { userId: string }
         search: { page: number }
+        matches: Array<MakeRouteMatchUnion>
       }>()
     },
   })
@@ -637,6 +647,7 @@ test('when creating a child route with params, search with beforeLoad from the r
         cause: 'preload' | 'enter' | 'stay'
         context: { userId: string }
         search: { page: number }
+        matches: Array<MakeRouteMatchUnion>
       }>()
     },
   })
@@ -660,6 +671,7 @@ test('when creating a child route with params, search with routeContext, beforeL
         cause: 'preload' | 'enter' | 'stay'
         context: { userId: string }
         search: { page: number }
+        matches: Array<MakeRouteMatchUnion>
       }>()
       return {
         env: 'env1',
@@ -676,6 +688,7 @@ test('when creating a child route with params, search with routeContext, beforeL
         cause: 'preload' | 'enter' | 'stay'
         context: { userId: string; env: string }
         search: { page: number }
+        matches: Array<MakeRouteMatchUnion>
       }>()
       return { permission: 'view' } as const
     },
@@ -774,6 +787,7 @@ test('when creating a child route with routeContext from a parent with routeCont
         cause: 'preload' | 'enter' | 'stay'
         context: { userId: string }
         search: {}
+        matches: Array<MakeRouteMatchUnion>
       }>()
 
       return { invoiceId: 'invoiceId1' }
@@ -794,6 +808,7 @@ test('when creating a child route with routeContext from a parent with routeCont
         cause: 'preload' | 'enter' | 'stay'
         context: { userId: string; invoiceId: string }
         search: {}
+        matches: Array<MakeRouteMatchUnion>
       }>()
 
       return { detailId: 'detailId1' }
@@ -837,6 +852,7 @@ test('when creating a child route with beforeLoad from a parent with beforeLoad'
         cause: 'preload' | 'enter' | 'stay'
         context: { userId: string }
         search: {}
+        matches: Array<MakeRouteMatchUnion>
       }>()
       return { invoiceId: 'invoiceId1' }
     },
@@ -856,6 +872,7 @@ test('when creating a child route with beforeLoad from a parent with beforeLoad'
         cause: 'preload' | 'enter' | 'stay'
         context: { userId: string; invoiceId: string }
         search: {}
+        matches: Array<MakeRouteMatchUnion>
       }>()
       return { detailId: 'detailId1' }
     },
@@ -899,6 +916,7 @@ test('when creating a child route with routeContext, beforeLoad, search, params,
         cause: 'preload' | 'enter' | 'stay'
         context: { userId: string }
         search: { page: number }
+        matches: Array<MakeRouteMatchUnion>
       }>()
       return { env: 'env1' }
     },
@@ -913,6 +931,7 @@ test('when creating a child route with routeContext, beforeLoad, search, params,
         cause: 'preload' | 'enter' | 'stay'
         context: { userId: string; env: string }
         search: { page: number }
+        matches: Array<MakeRouteMatchUnion>
       }>()
       return { invoicePermissions: ['view'] as const }
     },
@@ -942,6 +961,7 @@ test('when creating a child route with routeContext, beforeLoad, search, params,
           invoicePermissions: readonly ['view']
         }
         search: { page: number; detailPage: number }
+        matches: Array<MakeRouteMatchUnion>
       }>()
       return { detailEnv: 'detailEnv' }
     },
@@ -961,6 +981,7 @@ test('when creating a child route with routeContext, beforeLoad, search, params,
           invoicePermissions: readonly ['view']
         }
         search: { page: number; detailPage: number }
+        matches: Array<MakeRouteMatchUnion>
       }>()
       return { detailsPermissions: ['view'] as const }
     },