Repository: TanStack/router
Pull request #2066 (2024-07-31 14:55:32)

fix(react-router): when navigating from a index the types should resolve to a valid route
There is an issue in the types where `from` is an index route but there is no `to` or the resolve path is the same as `from`. It means that

`<Link from='/posts/' />` always requires a `search` param because the resolved route is incorrect and returns `never`

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

CI is running for commit 440301aa8e4e5f288cfc35be0a45c2b1c22337af.

[📂 Click to track the progress, see the status, the terminal output, and the build insights.](https://cloud.nx.app/cipes/66aa50807520712164491c16?utm_source=pull-request&utm_medium=comment)


---

Sent with 💌 from [NxCloud.](https://nx.app?utm_source=pull-request&utm_medium=comment)
pkg-pr-new[bot]: 
_commit: <a href="https://github.com/TanStack/router/runs/28165643941"><code>440301a</code></a>_


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


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


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


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


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


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


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


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


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


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


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


[Open in Stackblitz](https://pkg.pr.new/template/96bfe5d0-889e-42b1-8302-e90d5eb7c032)
<details><summary><b>More templates</b></summary><p>

- [tanstack-router-react-example-authenticated-routes](https://pkg.pr.new/template/41471943-bf19-413d-a1ef-9c24fa8632f6)
- [tanstack-router-react-example-basic](https://pkg.pr.new/template/0a20e651-13d1-411d-afe5-0483fd22fe9d)
- [tanstack-router-react-example-basic-default-search-params](https://pkg.pr.new/template/4bfb8320-4bd9-4921-b424-0a5a93e7ff1c)
- [tanstack-router-react-example-basic-file-based](https://pkg.pr.new/template/535a4f41-bf72-45c0-984a-01841b206387)
- [tanstack-router-react-example-basic-file-based-codesplitting](https://pkg.pr.new/template/ff7cd756-6b42-493a-8890-5917a86ca8ba)
- [tanstack-router-react-example-react-query](https://pkg.pr.new/template/029ca749-3cdc-4f2b-8bbd-f942852ee6c8)
- [tanstack-router-react-example-basic-react-query-file-based](https://pkg.pr.new/template/da396c22-96b0-44d8-b834-dc396781bdac)
- [tanstack-router-react-example-basic-ssr-file-based](https://pkg.pr.new/template/643e0d7a-c566-4dca-a7be-e642eb8c064b)
- [tanstack-router-react-example-basic-ssr-streaming-file-based](https://pkg.pr.new/template/2466f7e5-b554-4075-9c43-394bb437d71d)
- [tanstack-router-react-example-deferred-data](https://pkg.pr.new/template/f3f0fc15-fc6e-4950-8447-33fbd59a5426)
- [tanstack-router-react-example-kitchen-sink](https://pkg.pr.new/template/df115f4a-2a48-4daa-9e13-0ad398912dc2)
- [tanstack-router-react-example-kitchen-sink-file-based](https://pkg.pr.new/template/cf857adc-7175-4bf1-9551-670b74aa912e)
- [tanstack-router-react-example-kitchen-sink-react-query](https://pkg.pr.new/template/b2bd3329-6136-4a89-b533-079225992b6d)
- [tanstack-router-react-example-kitchen-sink-react-query-file-based](https://pkg.pr.new/template/b6125a18-0d25-45fe-aee7-a395af4b8cf3)
- [tanstack-router-react-example-large-file-based](https://pkg.pr.new/template/b78849b1-40a3-4764-8fd9-6dbba9240900)
- [tanstack-router-react-example-location-masking](https://pkg.pr.new/template/b08d86d8-9a49-48b9-917f-c8bdcbea9c72)
- [tanstack-router-react-example-navigation-blocking](https://pkg.pr.new/template/a5c67758-b07c-43cb-ab15-5e7744dac775)
- [tanstack-router-react-example-quickstart](https://pkg.pr.new/template/a9e36275-331b-40bc-bca7-e8cb78c58a60)
- [tanstack-router-react-example-quickstart-file-based](https://pkg.pr.new/template/3e25e7df-0db6-4b7c-831f-4c4552d373f0)
- [tanstack-router-react-example-quickstart-rspack-file-based](https://pkg.pr.new/template/3a1c6aac-9136-4d8b-8975-a72beb30110e)
- [tanstack-router-react-example-quickstart-webpack-file-based](https://pkg.pr.new/template/2451f3d1-efca-460f-8c32-34acdd49ab0e)
- [tanstack-router-react-example-scroll-restoration](https://pkg.pr.new/template/cd11554a-a8ef-4976-bc94-519ccaf336ba)
- [tanstack-router-example-react-start-basic](https://pkg.pr.new/template/3476b6cd-8842-4ed4-a5e5-07053a8fd2ff)
- [tanstack-router-example-react-start-basic-counter](https://pkg.pr.new/template/23265e3e-ffba-40cf-b366-2fde1442a929)
- [tanstack-router-example-react-start-basic-react-query](https://pkg.pr.new/template/c6bd84a1-6f82-4200-a081-11ba6c0a0082)
- [tanstack-router-example-react-start-basic-rsc](https://pkg.pr.new/template/b26c7887-c017-4ac2-b862-97d11f73d622)
- [tanstack-router-example-react-start-basic-trellaux](https://pkg.pr.new/template/f9d2a1d0-5973-4eb6-b01d-1f7d98b73f6f)
- [tanstack-router-react-example-with-trpc-react-query](https://pkg.pr.new/template/2c97ff3c-180b-4802-9280-936ae4b9181f)
- [tanstack-router-react-example-waku-rsc](https://pkg.pr.new/template/373466a4-432c-455d-b301-edf4ee645b79)
- [tanstack-router-react-example-with-bling](https://pkg.pr.new/template/851eb894-af87-45c4-a034-9618f38b6ab0)
- [tanstack-router-react-example-with-framer-motion](https://pkg.pr.new/template/ae192cf4-f284-44e3-8b96-f5122f9cd334)
- [tanstack-router-react-example-with-trpc](https://pkg.pr.new/template/8e9dce91-d29b-458f-9057-96be4a5a2139)

</p></details>
      
    


Patch:
diff --git a/packages/react-router/src/link.tsx b/packages/react-router/src/link.tsx
index e7707e881..c1624a6f6 100644
--- a/packages/react-router/src/link.tsx
+++ b/packages/react-router/src/link.tsx
@@ -258,7 +258,7 @@ export type ResolveRoute<
   TTo,
   TPath = ResolveRelativePath<TFrom, TTo>,
 > = TPath extends string
-  ? string extends TTo
+  ? TFrom extends TPath
     ? RouteByPath<TRouter['routeTree'], TPath>
     : RouteByToPath<TRouter, TPath>
   : never


Test patch:
diff --git a/packages/react-router/tests/link.test-d.tsx b/packages/react-router/tests/link.test-d.tsx
index 1aa58f82b..8b27666d2 100644
--- a/packages/react-router/tests/link.test-d.tsx
+++ b/packages/react-router/tests/link.test-d.tsx
@@ -484,6 +484,91 @@ test('when navigating from a route with no params and no search to the current r
     .parameter(0)
     .toHaveProperty('to')
     .toEqualTypeOf<'./$postId/' | './$postId' | undefined | './'>()
+
+  expectTypeOf(Link<DefaultRouter, '/posts/', './'>)
+    .parameter(0)
+    .toHaveProperty('search')
+    .exclude<Function>()
+    .toEqualTypeOf<{ rootPage?: number } | undefined | true>()
+
+  expectTypeOf(Link<DefaultRouterObjects, '/posts/', './'>)
+    .parameter(0)
+    .toHaveProperty('search')
+    .exclude<Function>()
+    .toEqualTypeOf<{ rootPage?: number } | undefined | true>()
+
+  expectTypeOf(Link<RouterAlwaysTrailingSlashes, '/posts/', './'>)
+    .parameter(0)
+    .toHaveProperty('search')
+    .exclude<Function>()
+    .toEqualTypeOf<{ rootPage?: number } | undefined | true>()
+
+  expectTypeOf(Link<RouterNeverTrailingSlashes, '/posts/', './'>)
+    .parameter(0)
+    .toHaveProperty('search')
+    .exclude<Function>()
+    .toEqualTypeOf<{ rootPage?: number } | undefined | true>()
+
+  expectTypeOf(Link<RouterPreserveTrailingSlashes, '/posts/', './'>)
+    .parameter(0)
+    .toHaveProperty('search')
+    .exclude<Function>()
+    .toEqualTypeOf<{ rootPage?: number } | undefined | true>()
+
+  expectTypeOf(Link<DefaultRouter, '/posts/', './'>)
+    .parameter(0)
+    .toHaveProperty('search')
+    .returns.toEqualTypeOf<{ rootPage?: number }>()
+
+  expectTypeOf(Link<DefaultRouterObjects, '/posts/', './'>)
+    .parameter(0)
+    .toHaveProperty('search')
+    .returns.toEqualTypeOf<{ rootPage?: number }>()
+
+  expectTypeOf(Link<RouterAlwaysTrailingSlashes, '/posts/', './'>)
+    .parameter(0)
+    .toHaveProperty('search')
+    .returns.toEqualTypeOf<{ rootPage?: number }>()
+
+  expectTypeOf(Link<RouterNeverTrailingSlashes, '/posts/', './'>)
+    .parameter(0)
+    .toHaveProperty('search')
+    .returns.toEqualTypeOf<{ rootPage?: number }>()
+
+  expectTypeOf(Link<RouterPreserveTrailingSlashes, '/posts/', './'>)
+    .parameter(0)
+    .toHaveProperty('search')
+    .returns.toEqualTypeOf<{ rootPage?: number }>()
+
+  expectTypeOf(Link<DefaultRouter, '/posts/', './'>)
+    .parameter(0)
+    .toHaveProperty('search')
+    .parameter(0)
+    .toEqualTypeOf<{ rootPage?: number }>()
+
+  expectTypeOf(Link<DefaultRouterObjects, '/posts/', './'>)
+    .parameter(0)
+    .toHaveProperty('search')
+    .parameter(0)
+    .toEqualTypeOf<{ rootPage?: number }>()
+
+  expectTypeOf(Link<RouterAlwaysTrailingSlashes, '/posts/', './'>)
+    .parameter(0)
+    .toHaveProperty('search')
+    .parameter(0)
+    .toEqualTypeOf<{ rootPage?: number }>()
+
+  expectTypeOf(Link<RouterNeverTrailingSlashes, '/posts/', './'>)
+    .parameter(0)
+    .toHaveProperty('search')
+    .parameter(0)
+    .toEqualTypeOf<{ rootPage?: number }>()
+
+  expectTypeOf(Link<RouterPreserveTrailingSlashes, '/posts/', './'>)
+    .parameter(0)
+    .toHaveProperty('search')
+    .parameter(0)
+    .toEqualTypeOf<{ rootPage?: number }>()
 })
 
 test('when navigating from a route with no params and no search to the parent route', () => {