Repository: TanStack/router
Pull request #1703 (2024-06-03 18:20:37)

fix: `from` was being ignored when the pathname included params or a pathless route
When `from` included a `path` which had `params` it was being ignored when the location was being built. Same with a layout route.

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

CI is running for commit e492a2f82f5e4eaa88a1d1204ccc85cd6c4501ba.

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


---

Sent with 💌 from [NxCloud.](https://nx.app?utm_source=pull-request&utm_medium=comment)

Patch:
diff --git a/examples/react/authenticated-routes/package.json b/examples/react/authenticated-routes/package.json
index 786c080b3..ba4b23ea0 100644
--- a/examples/react/authenticated-routes/package.json
+++ b/examples/react/authenticated-routes/package.json
@@ -9,8 +9,8 @@
     "start": "vite"
   },
   "dependencies": {
-    "@tanstack/react-router": "^1.34.9",
-    "@tanstack/router-devtools": "^1.34.9",
+    "@tanstack/react-router": "^1.35.0",
+    "@tanstack/router-devtools": "^1.35.0",
     "@tanstack/router-vite-plugin": "^1.34.8",
     "redaxios": "^0.5.0",
     "immer": "^10.0.3",
diff --git a/examples/react/basic-default-search-params/package.json b/examples/react/basic-default-search-params/package.json
index e63501892..19c5c470b 100644
--- a/examples/react/basic-default-search-params/package.json
+++ b/examples/react/basic-default-search-params/package.json
@@ -10,8 +10,8 @@
   },
   "dependencies": {
     "@tanstack/react-query": "^5.17.8",
-    "@tanstack/react-router": "^1.34.9",
-    "@tanstack/router-devtools": "^1.34.9",
+    "@tanstack/react-router": "^1.35.0",
+    "@tanstack/router-devtools": "^1.35.0",
     "redaxios": "^0.5.0",
     "react": "^18.2.0",
     "react-dom": "^18.2.0",
diff --git a/examples/react/basic-file-based-codesplitting/package.json b/examples/react/basic-file-based-codesplitting/package.json
index a8ed8b3bd..b8c938373 100644
--- a/examples/react/basic-file-based-codesplitting/package.json
+++ b/examples/react/basic-file-based-codesplitting/package.json
@@ -9,8 +9,8 @@
     "start": "vite"
   },
   "dependencies": {
-    "@tanstack/react-router": "^1.34.9",
-    "@tanstack/router-devtools": "^1.34.9",
+    "@tanstack/react-router": "^1.35.0",
+    "@tanstack/router-devtools": "^1.35.0",
     "@tanstack/router-vite-plugin": "^1.34.8",
     "redaxios": "^0.5.0",
     "immer": "^10.0.3",
diff --git a/examples/react/basic-file-based/package.json b/examples/react/basic-file-based/package.json
index 9067c2e61..c1be94177 100644
--- a/examples/react/basic-file-based/package.json
+++ b/examples/react/basic-file-based/package.json
@@ -9,8 +9,8 @@
     "start": "vite"
   },
   "dependencies": {
-    "@tanstack/react-router": "^1.34.9",
-    "@tanstack/router-devtools": "^1.34.9",
+    "@tanstack/react-router": "^1.35.0",
+    "@tanstack/router-devtools": "^1.35.0",
     "@tanstack/router-vite-plugin": "^1.34.8",
     "redaxios": "^0.5.0",
     "immer": "^10.0.3",
diff --git a/examples/react/basic-react-query-file-based/package.json b/examples/react/basic-react-query-file-based/package.json
index eb133984e..a8cb7ddb7 100644
--- a/examples/react/basic-react-query-file-based/package.json
+++ b/examples/react/basic-react-query-file-based/package.json
@@ -11,8 +11,8 @@
   "dependencies": {
     "@tanstack/react-query": "^5.17.8",
     "@tanstack/react-query-devtools": "^5.17.8",
-    "@tanstack/react-router": "^1.34.9",
-    "@tanstack/router-devtools": "^1.34.9",
+    "@tanstack/react-router": "^1.35.0",
+    "@tanstack/router-devtools": "^1.35.0",
     "@tanstack/router-vite-plugin": "^1.34.8",
     "redaxios": "^0.5.0",
     "immer": "^10.0.3",
diff --git a/examples/react/basic-react-query/package.json b/examples/react/basic-react-query/package.json
index b561b8b8f..4c164b2bf 100644
--- a/examples/react/basic-react-query/package.json
+++ b/examples/react/basic-react-query/package.json
@@ -11,8 +11,8 @@
   "dependencies": {
     "@tanstack/react-query": "^5.17.8",
     "@tanstack/react-query-devtools": "^5.17.8",
-    "@tanstack/react-router": "^1.34.9",
-    "@tanstack/router-devtools": "^1.34.9",
+    "@tanstack/react-router": "^1.35.0",
+    "@tanstack/router-devtools": "^1.35.0",
     "redaxios": "^0.5.0",
     "react": "^18.2.0",
     "react-dom": "^18.2.0"
diff --git a/examples/react/basic-ssr-file-based/package.json b/examples/react/basic-ssr-file-based/package.json
index c1a01296a..30e643364 100644
--- a/examples/react/basic-ssr-file-based/package.json
+++ b/examples/react/basic-ssr-file-based/package.json
@@ -12,9 +12,9 @@
     "debug": "node --inspect-brk server"
   },
   "dependencies": {
-    "@tanstack/react-router": "^1.34.9",
-    "@tanstack/start": "^1.34.9",
-    "@tanstack/router-devtools": "^1.34.9",
+    "@tanstack/react-router": "^1.35.0",
+    "@tanstack/start": "^1.35.0",
+    "@tanstack/router-devtools": "^1.35.0",
     "@tanstack/router-vite-plugin": "^1.34.8",
     "redaxios": "^0.5.0",
     "get-port": "^7.0.0",
diff --git a/examples/react/basic-ssr-streaming-file-based/package.json b/examples/react/basic-ssr-streaming-file-based/package.json
index ec496a004..907672815 100644
--- a/examples/react/basic-ssr-streaming-file-based/package.json
+++ b/examples/react/basic-ssr-streaming-file-based/package.json
@@ -12,9 +12,9 @@
     "debug": "node --inspect-brk server"
   },
   "dependencies": {
-    "@tanstack/react-router": "^1.34.9",
-    "@tanstack/start": "^1.34.9",
-    "@tanstack/router-devtools": "^1.34.9",
+    "@tanstack/react-router": "^1.35.0",
+    "@tanstack/start": "^1.35.0",
+    "@tanstack/router-devtools": "^1.35.0",
     "@tanstack/router-vite-plugin": "^1.34.8",
     "redaxios": "^0.5.0",
     "get-port": "^7.0.0",
diff --git a/examples/react/basic/package.json b/examples/react/basic/package.json
index 53263b06d..962559d47 100644
--- a/examples/react/basic/package.json
+++ b/examples/react/basic/package.json
@@ -10,8 +10,8 @@
   },
   "dependencies": {
     "@tanstack/react-query": "^5.17.8",
-    "@tanstack/react-router": "^1.34.9",
-    "@tanstack/router-devtools": "^1.34.9",
+    "@tanstack/react-router": "^1.35.0",
+    "@tanstack/router-devtools": "^1.35.0",
     "redaxios": "^0.5.0",
     "react": "^18.2.0",
     "react-dom": "^18.2.0"
diff --git a/examples/react/deferred-data/package.json b/examples/react/deferred-data/package.json
index 186be080e..5b47a49bb 100644
--- a/examples/react/deferred-data/package.json
+++ b/examples/react/deferred-data/package.json
@@ -9,8 +9,8 @@
     "start": "vite"
   },
   "dependencies": {
-    "@tanstack/react-router": "^1.34.9",
-    "@tanstack/router-devtools": "^1.34.9",
+    "@tanstack/react-router": "^1.35.0",
+    "@tanstack/router-devtools": "^1.35.0",
     "redaxios": "^0.5.0",
     "immer": "^10.0.3",
     "react": "^18.2.0",
diff --git a/examples/react/kitchen-sink-file-based/package.json b/examples/react/kitchen-sink-file-based/package.json
index daa4b9619..be4d6919a 100644
--- a/examples/react/kitchen-sink-file-based/package.json
+++ b/examples/react/kitchen-sink-file-based/package.json
@@ -9,8 +9,8 @@
     "start": "vite"
   },
   "dependencies": {
-    "@tanstack/react-router": "^1.34.9",
-    "@tanstack/router-devtools": "^1.34.9",
+    "@tanstack/react-router": "^1.35.0",
+    "@tanstack/router-devtools": "^1.35.0",
     "@tanstack/router-vite-plugin": "^1.34.8",
     "redaxios": "^0.5.0",
     "immer": "^10.0.3",
diff --git a/examples/react/kitchen-sink-react-query-file-based/package.json b/examples/react/kitchen-sink-react-query-file-based/package.json
index dbcc6019f..852ec53c8 100644
--- a/examples/react/kitchen-sink-react-query-file-based/package.json
+++ b/examples/react/kitchen-sink-react-query-file-based/package.json
@@ -11,8 +11,8 @@
   "dependencies": {
     "@tanstack/react-query": "^5.17.8",
     "@tanstack/react-query-devtools": "^5.17.8",
-    "@tanstack/react-router": "^1.34.9",
-    "@tanstack/router-devtools": "^1.34.9",
+    "@tanstack/react-router": "^1.35.0",
+    "@tanstack/router-devtools": "^1.35.0",
     "@tanstack/router-vite-plugin": "^1.34.8",
     "redaxios": "^0.5.0",
     "immer": "^10.0.3",
diff --git a/examples/react/kitchen-sink-react-query/package.json b/examples/react/kitchen-sink-react-query/package.json
index 2cb7a1c34..7af529142 100644
--- a/examples/react/kitchen-sink-react-query/package.json
+++ b/examples/react/kitchen-sink-react-query/package.json
@@ -11,8 +11,8 @@
   "dependencies": {
     "@tanstack/react-query": "^5.17.8",
     "@tanstack/react-query-devtools": "^5.17.8",
-    "@tanstack/react-router": "^1.34.9",
-    "@tanstack/router-devtools": "^1.34.9",
+    "@tanstack/react-router": "^1.35.0",
+    "@tanstack/router-devtools": "^1.35.0",
     "redaxios": "^0.5.0",
     "immer": "^10.0.3",
     "react": "^18.2.0",
diff --git a/examples/react/kitchen-sink/package.json b/examples/react/kitchen-sink/package.json
index 5f3664c25..d1a42d69f 100644
--- a/examples/react/kitchen-sink/package.json
+++ b/examples/react/kitchen-sink/package.json
@@ -9,8 +9,8 @@
     "start": "vite"
   },
   "dependencies": {
-    "@tanstack/react-router": "^1.34.9",
-    "@tanstack/router-devtools": "^1.34.9",
+    "@tanstack/react-router": "^1.35.0",
+    "@tanstack/router-devtools": "^1.35.0",
     "redaxios": "^0.5.0",
     "immer": "^10.0.3",
     "react": "^18.2.0",
diff --git a/examples/react/large-file-based/package.json b/examples/react/large-file-based/package.json
index a665c63d9..e573025ff 100644
--- a/examples/react/large-file-based/package.json
+++ b/examples/react/large-file-based/package.json
@@ -12,8 +12,8 @@
   },
   "dependencies": {
     "@tanstack/react-query": "^5.17.8",
-    "@tanstack/react-router": "^1.34.9",
-    "@tanstack/router-devtools": "^1.34.9",
+    "@tanstack/react-router": "^1.35.0",
+    "@tanstack/router-devtools": "^1.35.0",
     "@tanstack/router-vite-plugin": "^1.34.8",
     "redaxios": "^0.5.0",
     "immer": "^10.0.3",
diff --git a/examples/react/location-masking/package.json b/examples/react/location-masking/package.json
index 20c23127a..008386d1a 100644
--- a/examples/react/location-masking/package.json
+++ b/examples/react/location-masking/package.json
@@ -11,8 +11,8 @@
   "dependencies": {
     "@radix-ui/react-dialog": "^1.0.5",
     "@tanstack/react-query": "^5.17.8",
-    "@tanstack/react-router": "^1.34.9",
-    "@tanstack/router-devtools": "^1.34.9",
+    "@tanstack/react-router": "^1.35.0",
+    "@tanstack/router-devtools": "^1.35.0",
     "redaxios": "^0.5.0",
     "react": "^18.2.0",
     "react-dom": "^18.2.0"
diff --git a/examples/react/navigation-blocking/package.json b/examples/react/navigation-blocking/package.json
index af93dff31..2930b3769 100644
--- a/examples/react/navigation-blocking/package.json
+++ b/examples/react/navigation-blocking/package.json
@@ -10,8 +10,8 @@
   },
   "dependencies": {
     "@tanstack/react-query": "^5.17.8",
-    "@tanstack/react-router": "^1.34.9",
-    "@tanstack/router-devtools": "^1.34.9",
+    "@tanstack/react-router": "^1.35.0",
+    "@tanstack/router-devtools": "^1.35.0",
     "redaxios": "^0.5.0",
     "react": "^18.2.0",
     "react-dom": "^18.2.0"
diff --git a/examples/react/quickstart-file-based/package.json b/examples/react/quickstart-file-based/package.json
index bec63b666..61fe5ccf7 100644
--- a/examples/react/quickstart-file-based/package.json
+++ b/examples/react/quickstart-file-based/package.json
@@ -9,8 +9,8 @@
     "start": "vite"
   },
   "dependencies": {
-    "@tanstack/react-router": "^1.34.9",
-    "@tanstack/router-devtools": "^1.34.9",
+    "@tanstack/react-router": "^1.35.0",
+    "@tanstack/router-devtools": "^1.35.0",
     "@tanstack/router-vite-plugin": "^1.34.8",
     "redaxios": "^0.5.0",
     "immer": "^10.0.3",
diff --git a/examples/react/quickstart/package.json b/examples/react/quickstart/package.json
index 4a2f377c4..ed8bdc4e7 100644
--- a/examples/react/quickstart/package.json
+++ b/examples/react/quickstart/package.json
@@ -9,8 +9,8 @@
     "start": "vite"
   },
   "dependencies": {
-    "@tanstack/react-router": "^1.34.9",
-    "@tanstack/router-devtools": "^1.34.9",
+    "@tanstack/react-router": "^1.35.0",
+    "@tanstack/router-devtools": "^1.35.0",
     "react": "^18.2.0",
     "react-dom": "^18.2.0"
   },
diff --git a/examples/react/scroll-restoration/package.json b/examples/react/scroll-restoration/package.json
index 03a2de7e7..64787f45b 100644
--- a/examples/react/scroll-restoration/package.json
+++ b/examples/react/scroll-restoration/package.json
@@ -9,9 +9,9 @@
     "start": "vite"
   },
   "dependencies": {
-    "@tanstack/react-router": "^1.34.9",
+    "@tanstack/react-router": "^1.35.0",
     "@tanstack/react-virtual": "^3.0.1",
-    "@tanstack/router-devtools": "^1.34.9",
+    "@tanstack/router-devtools": "^1.35.0",
     "react": "^18.2.0",
     "react-dom": "^18.2.0"
   },
diff --git a/examples/react/start-basic-rsc/package.json b/examples/react/start-basic-rsc/package.json
index d6dd35e5f..06a41ebdf 100644
--- a/examples/react/start-basic-rsc/package.json
+++ b/examples/react/start-basic-rsc/package.json
@@ -12,10 +12,10 @@
     "format": "prettier --write '**/*' --ignore-unknown"
   },
   "dependencies": {
-    "@tanstack/react-router": "^1.34.9",
-    "@tanstack/router-devtools": "^1.34.9",
+    "@tanstack/react-router": "^1.35.0",
+    "@tanstack/router-devtools": "^1.35.0",
     "@tanstack/router-vite-plugin": "^1.34.8",
-    "@tanstack/start": "^1.34.9",
+    "@tanstack/start": "^1.35.0",
     "redaxios": "^0.5.0",
     "isbot": "^3.7.0",
     "react": "^18.3.1",
diff --git a/examples/react/start-basic/package.json b/examples/react/start-basic/package.json
index f730a48e9..2d3949fa9 100644
--- a/examples/react/start-basic/package.json
+++ b/examples/react/start-basic/package.json
@@ -14,10 +14,10 @@
     "test:e2e:replay": "playwright test --project=replay-chromium"
   },
   "dependencies": {
-    "@tanstack/react-router": "^1.34.9",
-    "@tanstack/router-devtools": "^1.34.9",
+    "@tanstack/react-router": "^1.35.0",
+    "@tanstack/router-devtools": "^1.35.0",
     "@tanstack/router-vite-plugin": "^1.34.8",
-    "@tanstack/start": "^1.34.9",
+    "@tanstack/start": "^1.35.0",
     "@typescript-eslint/parser": "^7.2.0",
     "@vitejs/plugin-react": "^4",
     "dotenv": "^16.4.5",
diff --git a/examples/react/start-trellaux/package.json b/examples/react/start-trellaux/package.json
index c084d844c..f46ba7918 100644
--- a/examples/react/start-trellaux/package.json
+++ b/examples/react/start-trellaux/package.json
@@ -14,10 +14,10 @@
   "dependencies": {
     "@tanstack/react-query": "^5.40.0",
     "@tanstack/react-query-devtools": "^5.40.0",
-    "@tanstack/react-router": "^1.34.9",
-    "@tanstack/router-devtools": "^1.34.9",
+    "@tanstack/react-router": "^1.35.0",
+    "@tanstack/router-devtools": "^1.35.0",
     "@tanstack/router-vite-plugin": "^1.34.1",
-    "@tanstack/start": "^1.34.9",
+    "@tanstack/start": "^1.35.0",
     "@typescript-eslint/parser": "^7.2.0",
     "@vitejs/plugin-react": "^4",
     "isbot": "^3.7.0",
diff --git a/examples/react/wip-trpc-react-query/package.json b/examples/react/wip-trpc-react-query/package.json
index 2a27101a4..6a01be4f7 100644
--- a/examples/react/wip-trpc-react-query/package.json
+++ b/examples/react/wip-trpc-react-query/package.json
@@ -13,8 +13,8 @@
   "dependencies": {
     "@tanstack/react-query": "^4.36.1",
     "@tanstack/react-query-devtools": "^4.36.1",
-    "@tanstack/react-router": "^1.34.9",
-    "@tanstack/router-devtools": "^1.34.9",
+    "@tanstack/react-router": "^1.35.0",
+    "@tanstack/router-devtools": "^1.35.0",
     "@trpc/client": "^10.45.0",
     "@trpc/react-query": "^10.45.0",
     "@trpc/server": "^10.45.0",
diff --git a/examples/react/wip-waku-rsc/package.json b/examples/react/wip-waku-rsc/package.json
index 1ce3b580c..60657749f 100644
--- a/examples/react/wip-waku-rsc/package.json
+++ b/examples/react/wip-waku-rsc/package.json
@@ -10,8 +10,8 @@
   },
   "dependencies": {
     "@hono/node-server": "^1.4.1",
-    "@tanstack/react-router": "^1.34.9",
-    "@tanstack/router-devtools": "^1.34.9",
+    "@tanstack/react-router": "^1.35.0",
+    "@tanstack/router-devtools": "^1.35.0",
     "hono": "^3.12.0",
     "react": "18.3.0-canary-0cdfef19b-20231211",
     "react-dom": "18.3.0-canary-0cdfef19b-20231211",
diff --git a/examples/react/wip-with-bling/package.json b/examples/react/wip-with-bling/package.json
index a3eef7945..69afdb0f7 100644
--- a/examples/react/wip-with-bling/package.json
+++ b/examples/react/wip-with-bling/package.json
@@ -13,10 +13,10 @@
   },
   "dependencies": {
     "@tanstack/bling": "^0.5.0",
-    "@tanstack/react-router": "^1.34.9",
-    "@tanstack/start": "^1.34.9",
+    "@tanstack/react-router": "^1.35.0",
+    "@tanstack/start": "^1.35.0",
     "@tanstack/react-store": "^0.2.1",
-    "@tanstack/router-devtools": "^1.34.9",
+    "@tanstack/router-devtools": "^1.35.0",
     "redaxios": "^0.5.0",
     "fastify": "^4.25.2",
     "get-port": "^7.0.0",
diff --git a/examples/react/wip-with-framer-motion/package.json b/examples/react/wip-with-framer-motion/package.json
index d75626a74..ece0891de 100644
--- a/examples/react/wip-with-framer-motion/package.json
+++ b/examples/react/wip-with-framer-motion/package.json
@@ -9,8 +9,8 @@
     "start": "vite"
   },
   "dependencies": {
-    "@tanstack/react-router": "^1.34.9",
-    "@tanstack/router-devtools": "^1.34.9",
+    "@tanstack/react-router": "^1.35.0",
+    "@tanstack/router-devtools": "^1.35.0",
     "redaxios": "^0.5.0",
     "framer-motion": "^10.17.9",
     "immer": "^10.0.3",
diff --git a/examples/react/with-trpc/package.json b/examples/react/with-trpc/package.json
index 7ac7d2d3e..9aae727fe 100644
--- a/examples/react/with-trpc/package.json
+++ b/examples/react/with-trpc/package.json
@@ -13,8 +13,8 @@
   "dependencies": {
     "@tanstack/react-query": "^4.36.1",
     "@tanstack/react-query-devtools": "^4.36.1",
-    "@tanstack/react-router": "^1.34.9",
-    "@tanstack/router-devtools": "^1.34.9",
+    "@tanstack/react-router": "^1.35.0",
+    "@tanstack/router-devtools": "^1.35.0",
     "@trpc/client": "^10.45.0",
     "@trpc/react-query": "^10.45.0",
     "@trpc/server": "^10.45.0",
diff --git a/packages/react-router/package.json b/packages/react-router/package.json
index 5c221807a..6c1893aa3 100644
--- a/packages/react-router/package.json
+++ b/packages/react-router/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@tanstack/react-router",
-  "version": "1.34.9",
+  "version": "1.35.0",
   "description": "",
   "author": "Tanner Linsley",
   "license": "MIT",
diff --git a/packages/react-router/src/index.tsx b/packages/react-router/src/index.tsx
index 6e5e5c24d..47f151341 100644
--- a/packages/react-router/src/index.tsx
+++ b/packages/react-router/src/index.tsx
@@ -154,7 +154,6 @@ export {
   type ResolveFullSearchSchema,
   type ResolveFullSearchSchemaInput,
   type AnyRoute,
-  type ResolveAllParams,
   type RouteConstraints,
   type AnyRootRoute,
   type RootSearchSchema,
diff --git a/packages/react-router/src/link.tsx b/packages/react-router/src/link.tsx
index 77e96606c..8c3682910 100644
--- a/packages/react-router/src/link.tsx
+++ b/packages/react-router/src/link.tsx
@@ -8,9 +8,10 @@ import type { AnyRouter, ParsedLocation } from '.'
 import type { HistoryState } from '@tanstack/history'
 import type { AnyRoute, RootSearchSchema } from './route'
 import type {
+  AllParams,
   CatchAllPaths,
-  ParseRoute,
-  ParseRouteWithoutBranches,
+  FullSearchSchema,
+  FullSearchSchemaInput,
   RouteByPath,
   RouteByToPath,
   RoutePaths,
@@ -257,15 +258,11 @@ export type ResolveRoute<
   TFrom,
   TTo,
   TPath = ResolveRelativePath<TFrom, TTo>,
-> = string extends TPath
-  ? ParseRouteWithoutBranches<TRouter['routeTree']>
-  : TPath extends CatchAllPaths
-    ? ParseRouteWithoutBranches<TRouter['routeTree']>
-    : TPath extends string
-      ? string extends TTo
-        ? RouteByPath<TRouter['routeTree'], TPath>
-        : RouteByToPath<TRouter, TPath>
-      : never
+> = TPath extends string
+  ? string extends TTo
+    ? RouteByPath<TRouter['routeTree'], TPath>
+    : RouteByToPath<TRouter, TPath>
+  : never
 
 type PostProcessParams<
   T,
@@ -275,17 +272,19 @@ type PostProcessParams<
 type ResolveFromParamType<TParamVariant extends ParamVariant> =
   TParamVariant extends 'PATH' ? 'allParams' : 'fullSearchSchema'
 
+type ResolveFromAllParams<
+  TRouter extends AnyRouter,
+  TParamVariant extends ParamVariant,
+> = TParamVariant extends 'PATH'
+  ? AllParams<TRouter['routeTree']>
+  : FullSearchSchema<TRouter['routeTree']>
+
 type ResolveFromParams<
   TRouter extends AnyRouter,
   TParamVariant extends ParamVariant,
   TFrom,
 > = string extends TFrom
-  ? PostProcessParams<
-      ParseRoute<
-        TRouter['routeTree']
-      >['types'][ResolveFromParamType<TParamVariant>],
-      TParamVariant
-    >
+  ? ResolveFromAllParams<TRouter, TParamVariant>
   : RouteByPath<
       TRouter['routeTree'],
       TFrom
@@ -294,16 +293,33 @@ type ResolveFromParams<
 type ResolveToParamType<TParamVariant extends ParamVariant> =
   TParamVariant extends 'PATH' ? 'allParams' : 'fullSearchSchemaInput'
 
+type ResolveAllToParams<
+  TRouter extends AnyRouter,
+  TParamVariant extends ParamVariant,
+> = TParamVariant extends 'PATH'
+  ? AllParams<TRouter['routeTree']>
+  : FullSearchSchemaInput<TRouter['routeTree']>
+
 export type ResolveToParams<
   TRouter extends AnyRouter,
   TParamVariant extends ParamVariant,
   TFrom,
   TTo,
-  TRoute extends AnyRoute = ResolveRoute<TRouter, TFrom, TTo>,
-> = PostProcessParams<
-  TRoute['types'][ResolveToParamType<TParamVariant>],
-  TParamVariant
->
+> =
+  ResolveRelativePath<TFrom, TTo> extends infer TPath
+    ? string extends TPath
+      ? ResolveAllToParams<TRouter, TParamVariant>
+      : TPath extends CatchAllPaths
+        ? ResolveAllToParams<TRouter, TParamVariant>
+        : PostProcessParams<
+            ResolveRoute<
+              TRouter,
+              TFrom,
+              TTo
+            >['types'][ResolveToParamType<TParamVariant>],
+            TParamVariant
+          >
+    : never
 
 type ResolveRelativeToParams<
   TRouter extends AnyRouter,
@@ -369,14 +385,8 @@ export interface MakeRequiredSearchParams<
   search: MakeRequiredParamsReducer<TRouter, 'SEARCH', TFrom, TTo> & {}
 }
 
-export type IsRequiredParams<TParams> = keyof TParams extends infer K extends
-  keyof TParams
-  ? K extends any
-    ? undefined extends TParams[K]
-      ? never
-      : true
-    : never
-  : never
+export type IsRequiredParams<TParams> =
+  Record<never, never> extends TParams ? never : true
 
 export type IsRequired<
   TRouter extends AnyRouter,
@@ -384,13 +394,15 @@ export type IsRequired<
   TFrom,
   TTo,
 > =
-  string extends ResolveRelativePath<TFrom, TTo>
-    ? never
-    : ResolveRelativePath<TFrom, TTo> extends CatchAllPaths
+  ResolveRelativePath<TFrom, TTo> extends infer TPath
+    ? string extends TPath
       ? never
-      : IsRequiredParams<
-          ResolveRelativeToParams<TRouter, TParamVariant, TFrom, TTo>
-        >
+      : TPath extends CatchAllPaths
+        ? never
+        : IsRequiredParams<
+            ResolveRelativeToParams<TRouter, TParamVariant, TFrom, TTo>
+          >
+    : never
 
 export type SearchParamOptions<
   TRouter extends AnyRouter,
@@ -585,7 +597,6 @@ export function useLinkProps<
   // null for LinkUtils
 
   const dest = {
-    ...(options.to && { from: matchPathname }),
     ...options,
   }
 
diff --git a/packages/react-router/src/route.ts b/packages/react-router/src/route.ts
index f5e6ebc5d..e6170f533 100644
--- a/packages/react-router/src/route.ts
+++ b/packages/react-router/src/route.ts
@@ -16,14 +16,7 @@ import type { NavigateOptions, ParsePathParams, ToSubOptions } from './link'
 import type { ParsedLocation } from './location'
 import type { RouteById, RouteIds, RoutePaths } from './routeInfo'
 import type { AnyRouter, RegisteredRouter, Router } from './router'
-import type {
-  Assign,
-  Expand,
-  IsAny,
-  NoInfer,
-  PickRequired,
-  UnionToIntersection,
-} from './utils'
+import type { Assign, Expand, IsAny, NoInfer, PickRequired } from './utils'
 import type { BuildLocationFn, NavigateFn } from './RouterProvider'
 import type { NotFoundError } from './not-found'
 import type { LazyRoute } from './fileRoute'
@@ -52,8 +45,10 @@ export type RoutePathOptions<TCustomId, TPath> =
 
 export interface StaticDataRouteOption {}
 
-export type RoutePathOptionsIntersection<TCustomId, TPath> =
-  UnionToIntersection<RoutePathOptions<TCustomId, TPath>>
+export type RoutePathOptionsIntersection<TCustomId, TPath> = {
+  path: TPath
+  id: TCustomId
+}
 
 export type RouteOptions<
   TParentRoute extends AnyRoute = AnyRoute,
@@ -474,11 +469,6 @@ export type ResolveAllParamsFromParent<
   ? TParams
   : Assign<TParentRoute['types']['allParams'], TParams>
 
-export type ResolveAllParams<TParentRoute extends AnyRoute, TParams> =
-  Record<never, string> extends TParentRoute['types']['allParams']
-    ? TParams
-    : UnionToIntersection<TParentRoute['types']['allParams'] & TParams> & {}
-
 export type RouteConstraints = {
   TParentRoute: AnyRoute
   TPath: string
@@ -618,7 +608,7 @@ export class Route<
     TSearchSchema
   >,
   in out TParams = Record<ParsePathParams<TPath>, string>,
-  in out TAllParams = ResolveAllParams<TParentRoute, TParams>,
+  in out TAllParams = ResolveAllParamsFromParent<TParentRoute, TParams>,
   TRouteContextReturn = RouteContext,
   in out TRouteContext = ResolveRouteContext<TRouteContextReturn>,
   in out TAllContext = Assign<
@@ -960,7 +950,7 @@ export function createRoute<
   >,
   TFullSearchSchema = ResolveFullSearchSchema<TParentRoute, TSearchSchema>,
   TParams = Record<ParsePathParams<TPath>, string>,
-  TAllParams = ResolveAllParams<TParentRoute, TParams>,
+  TAllParams = ResolveAllParamsFromParent<TParentRoute, TParams>,
   TRouteContextReturn = RouteContext,
   TRouteContext = ResolveRouteContext<TRouteContextReturn>,
   TAllContext = Assign<
diff --git a/packages/react-router/src/routeInfo.ts b/packages/react-router/src/routeInfo.ts
index 3b33d097a..f9d5f51b7 100644
--- a/packages/react-router/src/routeInfo.ts
+++ b/packages/react-router/src/routeInfo.ts
@@ -114,20 +114,25 @@ export type RouteByToPath<TRouter extends AnyRouter, TTo> = Extract<
   AnyRoute
 >
 
-export type FullSearchSchema<TRouteTree extends AnyRoute> = Expand<
-  MergeUnion<
-    Exclude<ParseRoute<TRouteTree>['types']['searchSchema'], RootSearchSchema>
+export type FullSearchSchema<TRouteTree extends AnyRoute> = MergeUnion<
+  Exclude<ParseRoute<TRouteTree>['types']['fullSearchSchema'], RootSearchSchema>
+>
+
+export type FullSearchSchemaInput<TRouteTree extends AnyRoute> = MergeUnion<
+  Exclude<
+    ParseRoute<TRouteTree>['types']['fullSearchSchemaInput'],
+    RootSearchSchema
   >
 >
 
-export type AllParams<TRouteTree extends AnyRoute> = Expand<
-  MergeUnion<ParseRoute<TRouteTree>['types']['params']>
+export type AllParams<TRouteTree extends AnyRoute> = MergeUnion<
+  ParseRoute<TRouteTree>['types']['allParams']
 >
 
-export type AllContext<TRouteTree extends AnyRoute> = Expand<
-  MergeUnion<ParseRoute<TRouteTree>['types']['allContext']>
+export type AllContext<TRouteTree extends AnyRoute> = MergeUnion<
+  ParseRoute<TRouteTree>['types']['allContext']
 >
 
-export type AllLoaderData<TRouteTree extends AnyRoute> = Expand<
-  MergeUnion<ParseRoute<TRouteTree>['types']['loaderData']>
+export type AllLoaderData<TRouteTree extends AnyRoute> = MergeUnion<
+  ParseRoute<TRouteTree>['types']['loaderData']
 >
diff --git a/packages/react-router/src/router.ts b/packages/react-router/src/router.ts
index 2d1abad62..551ac382a 100644
--- a/packages/react-router/src/router.ts
+++ b/packages/react-router/src/router.ts
@@ -1102,14 +1102,27 @@ export class Router<
     ): ParsedLocation => {
       let fromPath = this.latestLocation.pathname
       let fromSearch = dest.fromSearch || this.latestLocation.search
+      const looseRoutesByPath = this.routesByPath as Record<string, AnyRoute>
+
+      const fromRoute =
+        dest.from !== undefined
+          ? looseRoutesByPath[trimPathRight(dest.from)]
+          : undefined
 
       const fromMatches = this.matchRoutes(
         this.latestLocation.pathname,
         fromSearch,
       )
 
-      fromPath =
-        fromMatches.find((d) => d.id === dest.from)?.pathname || fromPath
+      const fromMatch = fromMatches.find((d) => d.routeId === fromRoute?.id)
+
+      fromPath = fromMatch?.pathname || fromPath
+
+      invariant(
+        dest.from == null || fromMatch != null,
+        'Could not find match for from: ' + dest.from,
+      )
+
       fromSearch = last(fromMatches)?.search || this.latestLocation.search
 
       const stayingMatches = matches?.filter((d) =>
@@ -1773,8 +1786,7 @@ export class Router<
                     preload: !!preload,
                     context: parentContext,
                     location,
-                    navigate: (opts: any) =>
-                      this.navigate({ ...opts, from: match.pathname }),
+                    navigate: (opts: any) => this.navigate({ ...opts }),
                     buildLocation: this.buildLocation,
                     cause: preload ? 'preload' : match.cause,
                   })) ?? ({} as any)
@@ -1827,8 +1839,7 @@ export class Router<
                   abortController: match.abortController,
                   context: match.context,
                   location,
-                  navigate: (opts) =>
-                    this.navigate({ ...opts, from: match.pathname } as any),
+                  navigate: (opts) => this.navigate({ ...opts } as any),
                   cause: preload ? 'preload' : match.cause,
                   route,
                 }
diff --git a/packages/react-router/src/useNavigate.tsx b/packages/react-router/src/useNavigate.tsx
index 52d048b30..93b8bdbd8 100644
--- a/packages/react-router/src/useNavigate.tsx
+++ b/packages/react-router/src/useNavigate.tsx
@@ -29,7 +29,6 @@ export function useNavigate<
     (options: NavigateOptions) => {
       return router.navigate({
         ...options,
-        from: options.to ? router.state.resolvedLocation.pathname : undefined,
       })
     },
     [router],
@@ -63,7 +62,6 @@ export function Navigate<
 
   React.useEffect(() => {
     navigate({
-      from: props.to ? match.pathname : undefined,
       ...props,
     } as any)
     // eslint-disable-next-line react-hooks/exhaustive-deps
diff --git a/packages/react-router/src/utils.ts b/packages/react-router/src/utils.ts
index 95ef366f4..2601b73e4 100644
--- a/packages/react-router/src/utils.ts
+++ b/packages/react-router/src/utils.ts
@@ -26,12 +26,6 @@ export type Expand<T> = T extends object
     : never
   : T
 
-export type UnionToIntersection<T> = (
-  T extends any ? (k: T) => void : never
-) extends (k: infer I) => any
-  ? I
-  : never
-
 export type DeepPartial<T> = T extends object
   ? {
       [P in keyof T]?: DeepPartial<T[P]>
@@ -100,7 +94,7 @@ export type MergeUnionPrimitives<TUnion> = TUnion extends MergeUnionPrimitive
 
 export type MergeUnion<TUnion> =
   | MergeUnionPrimitives<TUnion>
-  | MergeUnionObject<MergeUnionObjects<TUnion>>
+  | MergeUnionObject<TUnion>
 
 export function last<T>(arr: Array<T>) {
   return arr[arr.length - 1]
diff --git a/packages/router-devtools/package.json b/packages/router-devtools/package.json
index bba7b3c33..8f3a73a95 100644
--- a/packages/router-devtools/package.json
+++ b/packages/router-devtools/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@tanstack/router-devtools",
-  "version": "1.34.9",
+  "version": "1.35.0",
   "description": "",
   "author": "Tanner Linsley",
   "license": "MIT",
diff --git a/packages/start/package.json b/packages/start/package.json
index 3b136f6b2..d5cab5674 100644
--- a/packages/start/package.json
+++ b/packages/start/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@tanstack/start",
-  "version": "1.34.9",
+  "version": "1.35.0",
   "description": "",
   "author": "Tanner Linsley",
   "license": "MIT",


Test patch:
diff --git a/packages/react-router/tests/link.test-d.tsx b/packages/react-router/tests/link.test-d.tsx
index dc7b09490..98724329e 100644
--- a/packages/react-router/tests/link.test-d.tsx
+++ b/packages/react-router/tests/link.test-d.tsx
@@ -1027,50 +1027,35 @@ test('when navigating to a route with params', () => {
     postId: string
   }>()
 
-  defaultRouterLinkParams
-    .parameter(0)
-    .toEqualTypeOf<
-      | {}
-      | { invoiceId: string }
-      | { postId: string }
-      | { invoiceId: string; detailId: string }
-    >()
+  defaultRouterLinkParams.parameter(0).toEqualTypeOf<{
+    invoiceId?: string
+    postId?: string
+    detailId?: string
+  }>()
 
-  defaultRouterObjectsLinkParams
-    .parameter(0)
-    .toEqualTypeOf<
-      | {}
-      | { invoiceId: string }
-      | { postId: string }
-      | { invoiceId: string; detailId: string }
-    >()
+  defaultRouterObjectsLinkParams.parameter(0).toEqualTypeOf<{
+    invoiceId?: string
+    postId?: string
+    detailId?: string
+  }>()
 
-  routerAlwaysTrailingSlashesLinkParams
-    .parameter(0)
-    .toEqualTypeOf<
-      | {}
-      | { invoiceId: string }
-      | { postId: string }
-      | { invoiceId: string; detailId: string }
-    >()
+  routerAlwaysTrailingSlashesLinkParams.parameter(0).toEqualTypeOf<{
+    invoiceId?: string
+    postId?: string
+    detailId?: string
+  }>()
 
-  routerNeverTrailingSlashesLinkParams
-    .parameter(0)
-    .toEqualTypeOf<
-      | {}
-      | { invoiceId: string }
-      | { postId: string }
-      | { invoiceId: string; detailId: string }
-    >()
+  routerNeverTrailingSlashesLinkParams.parameter(0).toEqualTypeOf<{
+    invoiceId?: string
+    postId?: string
+    detailId?: string
+  }>()
 
-  routerPreserveTrailingSlashesLinkParams
-    .parameter(0)
-    .toEqualTypeOf<
-      | {}
-      | { invoiceId: string }
-      | { postId: string }
-      | { invoiceId: string; detailId: string }
-    >()
+  routerPreserveTrailingSlashesLinkParams.parameter(0).toEqualTypeOf<{
+    invoiceId?: string
+    postId?: string
+    detailId?: string
+  }>()
 })
 
 test('when navigating from a route with no params to a route with params', () => {
@@ -1650,43 +1635,43 @@ test('when navigating to a union of routes with params', () => {
 
   expectTypeOf(DefaultRouterLink)
     .parameter(0)
-    .not.toMatchTypeOf<{ params: unknown }>()
+    .toMatchTypeOf<{ params: unknown }>()
 
   expectTypeOf(DefaultRouterObjectsLink)
     .parameter(0)
-    .not.toMatchTypeOf<{ params: unknown }>()
+    .toMatchTypeOf<{ params: unknown }>()
 
   expectTypeOf(RouterAlwaysTrailingSlashesLink)
     .parameter(0)
-    .not.toMatchTypeOf<{ params: unknown }>()
+    .toMatchTypeOf<{ params: unknown }>()
 
   expectTypeOf(RouterNeverTrailingSlashesLink)
     .parameter(0)
-    .not.toMatchTypeOf<{ params: unknown }>()
+    .toMatchTypeOf<{ params: unknown }>()
 
   expectTypeOf(RouterPreserveTrailingSlashesLink)
     .parameter(0)
-    .not.toMatchTypeOf<{ params: unknown }>()
+    .toMatchTypeOf<{ params: unknown }>()
 
   defaultRouterLinkParams
     .exclude<Function | boolean>()
-    .toEqualTypeOf<{ invoiceId: string } | { postId: string } | undefined>()
+    .toEqualTypeOf<{ invoiceId: string } | { postId: string }>()
 
   defaultRouterObjectsLinkParams
     .exclude<Function | boolean>()
-    .toEqualTypeOf<{ invoiceId: string } | { postId: string } | undefined>()
+    .toEqualTypeOf<{ invoiceId: string } | { postId: string }>()
 
   routerAlwaysTrailingSlashesLinkParams
     .exclude<Function | boolean>()
-    .toEqualTypeOf<{ invoiceId: string } | { postId: string } | undefined>()
+    .toEqualTypeOf<{ invoiceId: string } | { postId: string }>()
 
   routerNeverTrailingSlashesLinkParams
     .exclude<Function | boolean>()
-    .toEqualTypeOf<{ invoiceId: string } | { postId: string } | undefined>()
+    .toEqualTypeOf<{ invoiceId: string } | { postId: string }>()
 
   routerPreserveTrailingSlashesLinkParams
     .exclude<Function | boolean>()
-    .toEqualTypeOf<{ invoiceId: string } | { postId: string } | undefined>()
+    .toEqualTypeOf<{ invoiceId: string } | { postId: string }>()
 
   defaultRouterLinkParams.returns.toEqualTypeOf<
     { invoiceId: string } | { postId: string }
@@ -1708,50 +1693,35 @@ test('when navigating to a union of routes with params', () => {
     { invoiceId: string } | { postId: string }
   >()
 
-  defaultRouterLinkParams
-    .parameter(0)
-    .toEqualTypeOf<
-      | {}
-      | { invoiceId: string }
-      | { postId: string }
-      | { invoiceId: string; detailId: string }
-    >()
+  defaultRouterLinkParams.parameter(0).toEqualTypeOf<{
+    invoiceId?: string
+    postId?: string
+    detailId?: string
+  }>()
 
-  defaultRouterObjectsLinkParams
-    .parameter(0)
-    .toEqualTypeOf<
-      | {}
-      | { invoiceId: string }
-      | { postId: string }
-      | { invoiceId: string; detailId: string }
-    >()
+  defaultRouterObjectsLinkParams.parameter(0).toEqualTypeOf<{
+    invoiceId?: string
+    postId?: string
+    detailId?: string
+  }>()
 
-  routerAlwaysTrailingSlashesLinkParams
-    .parameter(0)
-    .toEqualTypeOf<
-      | {}
-      | { invoiceId: string }
-      | { postId: string }
-      | { invoiceId: string; detailId: string }
-    >()
+  routerAlwaysTrailingSlashesLinkParams.parameter(0).toEqualTypeOf<{
+    invoiceId?: string
+    postId?: string
+    detailId?: string
+  }>()
 
-  routerNeverTrailingSlashesLinkParams
-    .parameter(0)
-    .toEqualTypeOf<
-      | {}
-      | { invoiceId: string }
-      | { postId: string }
-      | { invoiceId: string; detailId: string }
-    >()
+  routerNeverTrailingSlashesLinkParams.parameter(0).toEqualTypeOf<{
+    invoiceId?: string
+    postId?: string
+    detailId?: string
+  }>()
 
-  routerPreserveTrailingSlashesLinkParams
-    .parameter(0)
-    .toEqualTypeOf<
-      | {}
-      | { invoiceId: string }
-      | { postId: string }
-      | { invoiceId: string; detailId: string }
-    >()
+  routerPreserveTrailingSlashesLinkParams.parameter(0).toEqualTypeOf<{
+    invoiceId?: string
+    postId?: string
+    detailId?: string
+  }>()
 })
 
 test('when navigating to a union of routes including the root', () => {
@@ -1885,50 +1855,35 @@ test('when navigating to a union of routes including the root', () => {
     { invoiceId: string } | { postId: string } | {}
   >()
 
-  defaultRouterLinkParams
-    .parameter(0)
-    .toEqualTypeOf<
-      | {}
-      | { invoiceId: string }
-      | { postId: string }
-      | { invoiceId: string; detailId: string }
-    >()
+  defaultRouterLinkParams.parameter(0).toEqualTypeOf<{
+    invoiceId?: string
+    postId?: string
+    detailId?: string
+  }>()
 
-  defaultRouterObjectsLinkParams
-    .parameter(0)
-    .toEqualTypeOf<
-      | {}
-      | { invoiceId: string }
-      | { postId: string }
-      | { invoiceId: string; detailId: string }
-    >()
+  defaultRouterObjectsLinkParams.parameter(0).toEqualTypeOf<{
+    invoiceId?: string
+    postId?: string
+    detailId?: string
+  }>()
 
-  routerAlwaysTrailingSlashesLinkParams
-    .parameter(0)
-    .toEqualTypeOf<
-      | {}
-      | { invoiceId: string }
-      | { postId: string }
-      | { invoiceId: string; detailId: string }
-    >()
+  routerAlwaysTrailingSlashesLinkParams.parameter(0).toEqualTypeOf<{
+    invoiceId?: string
+    postId?: string
+    detailId?: string
+  }>()
 
-  routerNeverTrailingSlashesLinkParams
-    .parameter(0)
-    .toEqualTypeOf<
-      | {}
-      | { invoiceId: string }
-      | { postId: string }
-      | { invoiceId: string; detailId: string }
-    >()
+  routerNeverTrailingSlashesLinkParams.parameter(0).toEqualTypeOf<{
+    invoiceId?: string
+    postId?: string
+    detailId?: string
+  }>()
 
-  routerPreserveTrailingSlashesLinkParams
-    .parameter(0)
-    .toEqualTypeOf<
-      | {}
-      | { invoiceId: string }
-      | { postId: string }
-      | { invoiceId: string; detailId: string }
-    >()
+  routerPreserveTrailingSlashesLinkParams.parameter(0).toEqualTypeOf<{
+    invoiceId?: string
+    postId?: string
+    detailId?: string
+  }>()
 })
 
 test('when navigating from a route with search params to the same route', () => {
@@ -2118,25 +2073,21 @@ test('when navigating to a route with search params', () => {
     page: number
   }>()
 
-  defaultRouterLinkSearch
-    .parameter(0)
-    .toEqualTypeOf<{} | { page: number } | { page?: number }>()
+  defaultRouterLinkSearch.parameter(0).toEqualTypeOf<{ page?: number }>()
 
-  defaultRouterObjectsLinkSearch
-    .parameter(0)
-    .toEqualTypeOf<{} | { page: number } | { page?: number }>()
+  defaultRouterObjectsLinkSearch.parameter(0).toEqualTypeOf<{ page?: number }>()
 
   routerAlwaysTrailingSlashesLinkSearch
     .parameter(0)
-    .toEqualTypeOf<{} | { page: number } | { page?: number }>()
+    .toEqualTypeOf<{ page?: number }>()
 
   routerNeverTrailingSlashesLinkSearch
     .parameter(0)
-    .toEqualTypeOf<{} | { page: number } | { page?: number }>()
+    .toEqualTypeOf<{ page?: number }>()
 
   routerPreserveTrailingSlashesLinkSearch
     .parameter(0)
-    .toEqualTypeOf<{} | { page: number } | { page?: number }>()
+    .toEqualTypeOf<{ page?: number }>()
 })
 
 test('when navigating to a route with optional search params', () => {
@@ -2253,25 +2204,21 @@ test('when navigating to a route with optional search params', () => {
     page?: number
   }>()
 
-  defaultRouterLinkSearch
-    .parameter(0)
-    .toEqualTypeOf<{} | { page: number } | { page?: number }>()
+  defaultRouterLinkSearch.parameter(0).toEqualTypeOf<{ page?: number }>()
 
-  defaultRouterObjectsLinkSearch
-    .parameter(0)
-    .toEqualTypeOf<{} | { page: number } | { page?: number }>()
+  defaultRouterObjectsLinkSearch.parameter(0).toEqualTypeOf<{ page?: number }>()
 
   routerAlwaysTrailingSlashesLinkSearch
     .parameter(0)
-    .toEqualTypeOf<{} | { page: number } | { page?: number }>()
+    .toEqualTypeOf<{ page?: number }>()
 
   routerNeverTrailingSlashesLinkSearch
     .parameter(0)
-    .toEqualTypeOf<{} | { page: number } | { page?: number }>()
+    .toEqualTypeOf<{ page?: number }>()
 
   routerPreserveTrailingSlashesLinkSearch
     .parameter(0)
-    .toEqualTypeOf<{} | { page: number } | { page?: number }>()
+    .toEqualTypeOf<{ page?: number }>()
 })
 
 test('when navigating from a route with no search params to a route with search params', () => {
@@ -2526,25 +2473,21 @@ test('when navigating to a union of routes with search params', () => {
     { page: number } | {}
   >()
 
-  defaultRouterLinkSearch
-    .parameter(0)
-    .toEqualTypeOf<{} | { page: number } | { page?: number }>()
+  defaultRouterLinkSearch.parameter(0).toEqualTypeOf<{ page?: number }>()
 
-  defaultRouterObjectsLinkSearch
-    .parameter(0)
-    .toEqualTypeOf<{} | { page: number } | { page?: number }>()
+  defaultRouterObjectsLinkSearch.parameter(0).toEqualTypeOf<{ page?: number }>()
 
   routerAlwaysTrailingSlashesSearch
     .parameter(0)
-    .toEqualTypeOf<{} | { page: number } | { page?: number }>()
+    .toEqualTypeOf<{ page?: number }>()
 
   routerNeverTrailingSlashesSearch
     .parameter(0)
-    .toEqualTypeOf<{} | { page: number } | { page?: number }>()
+    .toEqualTypeOf<{ page?: number }>()
 
   routerPreserveTrailingSlashesSearch
     .parameter(0)
-    .toEqualTypeOf<{} | { page: number } | { page?: number }>()
+    .toEqualTypeOf<{ page?: number }>()
 })
 
 test('when navigating to a union of routes with search params including the root', () => {
@@ -2664,23 +2607,19 @@ test('when navigating to a union of routes with search params including the root
     { page: number } | {}
   >()
 
-  defaultRouterSearch
-    .parameter(0)
-    .toEqualTypeOf<{} | { page: number } | { page?: number }>()
+  defaultRouterSearch.parameter(0).toEqualTypeOf<{ page?: number }>()
 
-  defaultRouterObjectsSearch
-    .parameter(0)
-    .toEqualTypeOf<{} | { page: number } | { page?: number }>()
+  defaultRouterObjectsSearch.parameter(0).toEqualTypeOf<{ page?: number }>()
 
   routerAlwaysTrailingSlashesLinkSearch
     .parameter(0)
-    .toEqualTypeOf<{} | { page: number } | { page?: number }>()
+    .toEqualTypeOf<{ page?: number }>()
 
   routerNeverTrailingSlashesLinkSearch
     .parameter(0)
-    .toEqualTypeOf<{} | { page: number } | { page?: number }>()
+    .toEqualTypeOf<{ page?: number }>()
 
   routerPreserveTrailingSlashesLinkSearch
     .parameter(0)
-    .toEqualTypeOf<{} | { page: number } | { page?: number }>()
+    .toEqualTypeOf<{ page?: number }>()
 })
diff --git a/packages/react-router/tests/link.test.tsx b/packages/react-router/tests/link.test.tsx
index a4a0099e4..4c1717c9a 100644
--- a/packages/react-router/tests/link.test.tsx
+++ b/packages/react-router/tests/link.test.tsx
@@ -1090,6 +1090,551 @@ describe('Link', () => {
 
     expect(await screen.findByText('Params: id1')).toBeInTheDocument()
   })
+
+  test('when navigating from /posts/$postId to /posts/$postId/info and the current route is /posts/$postId/details', async () => {
+    const rootRoute = createRootRoute()
+
+    const indexRoute = createRoute({
+      getParentRoute: () => rootRoute,
+      path: '/',
+      component: () => {
+        return (
+          <React.Fragment>
+            <h1>Index</h1>
+            <Link to="/posts">Posts</Link>
+            <Link to="/posts/$postId/details" params={{ postId: 'id1' }}>
+              To first post
+            </Link>
+          </React.Fragment>
+        )
+      },
+    })
+
+    const layoutRoute = createRoute({
+      getParentRoute: () => rootRoute,
+      id: '_layout',
+      component: () => {
+        return (
+          <>
+            <h1>Layout</h1>
+            <Outlet />
+          </>
+        )
+      },
+    })
+
+    const PostsComponent = () => {
+      return (
+        <React.Fragment>
+          <h1>Posts</h1>
+          <Outlet />
+        </React.Fragment>
+      )
+    }
+
+    const postsRoute = createRoute({
+      getParentRoute: () => layoutRoute,
+      path: 'posts',
+      component: PostsComponent,
+    })
+
+    const PostComponent = () => {
+      const params = useParams({ strict: false })
+      return (
+        <React.Fragment>
+          <span>Params: {params.postId}</span>
+          <Outlet />
+        </React.Fragment>
+      )
+    }
+
+    const postRoute = createRoute({
+      getParentRoute: () => postsRoute,
+      path: '$postId',
+      component: PostComponent,
+    })
+
+    const DetailsComponent = () => {
+      return (
+        <>
+          <h1>Details!</h1>
+          <Link from="/posts/$postId" to="/posts/$postId/info">
+            To Information
+          </Link>
+        </>
+      )
+    }
+
+    const detailsRoute = createRoute({
+      getParentRoute: () => postRoute,
+      path: 'details',
+      component: DetailsComponent,
+    })
+
+    const InformationComponent = () => {
+      return (
+        <React.Fragment>
+          <h1>Information</h1>
+        </React.Fragment>
+      )
+    }
+
+    const informationRoute = createRoute({
+      getParentRoute: () => postRoute,
+      path: 'info',
+      component: InformationComponent,
+    })
+
+    const router = createRouter({
+      routeTree: rootRoute.addChildren([
+        indexRoute,
+        layoutRoute.addChildren([
+          postsRoute.addChildren([
+            postRoute.addChildren([detailsRoute, informationRoute]),
+          ]),
+        ]),
+      ]),
+    })
+
+    render(<RouterProvider router={router} />)
+
+    const postsLink = await screen.findByRole('link', { name: 'To first post' })
+
+    expect(postsLink).toHaveAttribute('href', '/posts/id1/details')
+
+    fireEvent.click(postsLink)
+
+    expect(await screen.findByText('Params: id1')).toBeInTheDocument()
+
+    expect(window.location.pathname).toEqual('/posts/id1/details')
+
+    const informationLink = await screen.findByRole('link', {
+      name: 'To Information',
+    })
+
+    expect(informationLink).toHaveAttribute('href', '/posts/id1/info')
+
+    fireEvent.click(informationLink)
+
+    expect(await screen.findByText('Information')).toBeInTheDocument()
+
+    expect(window.location.pathname).toEqual('/posts/id1/info')
+
+    expect(await screen.findByText('Params: id1'))
+  })
+
+  test('when navigating from /posts/$postId to ./info and the current route is /posts/$postId/details', async () => {
+    const rootRoute = createRootRoute()
+
+    const indexRoute = createRoute({
+      getParentRoute: () => rootRoute,
+      path: '/',
+      component: () => {
+        return (
+          <React.Fragment>
+            <h1>Index</h1>
+            <Link to="/posts">Posts</Link>
+            <Link to="/posts/$postId/details" params={{ postId: 'id1' }}>
+              To first post
+            </Link>
+          </React.Fragment>
+        )
+      },
+    })
+
+    const layoutRoute = createRoute({
+      getParentRoute: () => rootRoute,
+      id: '_layout',
+      component: () => {
+        return (
+          <>
+            <h1>Layout</h1>
+            <Outlet />
+          </>
+        )
+      },
+    })
+
+    const PostsComponent = () => {
+      return (
+        <React.Fragment>
+          <h1>Posts</h1>
+          <Outlet />
+        </React.Fragment>
+      )
+    }
+
+    const postsRoute = createRoute({
+      getParentRoute: () => layoutRoute,
+      path: 'posts',
+      component: PostsComponent,
+    })
+
+    const PostComponent = () => {
+      const params = useParams({ strict: false })
+      return (
+        <React.Fragment>
+          <span>Params: {params.postId}</span>
+          <Outlet />
+        </React.Fragment>
+      )
+    }
+
+    const postRoute = createRoute({
+      getParentRoute: () => postsRoute,
+      path: '$postId',
+      component: PostComponent,
+    })
+
+    const DetailsComponent = () => {
+      return (
+        <>
+          <h1>Details!</h1>
+          <Link from="/posts/$postId" to="./info">
+            To Information
+          </Link>
+        </>
+      )
+    }
+
+    const detailsRoute = createRoute({
+      getParentRoute: () => postRoute,
+      path: 'details',
+      component: DetailsComponent,
+    })
+
+    const InformationComponent = () => {
+      return (
+        <React.Fragment>
+          <h1>Information</h1>
+        </React.Fragment>
+      )
+    }
+
+    const informationRoute = createRoute({
+      getParentRoute: () => postRoute,
+      path: 'info',
+      component: InformationComponent,
+    })
+
+    const router = createRouter({
+      routeTree: rootRoute.addChildren([
+        indexRoute,
+        layoutRoute.addChildren([
+          postsRoute.addChildren([
+            postRoute.addChildren([detailsRoute, informationRoute]),
+          ]),
+        ]),
+      ]),
+    })
+
+    render(<RouterProvider router={router} />)
+
+    const postsLink = await screen.findByRole('link', { name: 'To first post' })
+
+    expect(postsLink).toHaveAttribute('href', '/posts/id1/details')
+
+    fireEvent.click(postsLink)
+
+    expect(await screen.findByText('Params: id1')).toBeInTheDocument()
+
+    expect(window.location.pathname).toEqual('/posts/id1/details')
+
+    const informationLink = await screen.findByRole('link', {
+      name: 'To Information',
+    })
+
+    expect(informationLink).toHaveAttribute('href', '/posts/id1/info')
+
+    fireEvent.click(informationLink)
+
+    expect(await screen.findByText('Information')).toBeInTheDocument()
+
+    expect(window.location.pathname).toEqual('/posts/id1/info')
+
+    expect(await screen.findByText('Params: id1'))
+  })
+
+  test('when navigating from /posts/$postId to ../$postId and the current route is /posts/$postId/details', async () => {
+    const rootRoute = createRootRoute()
+
+    const indexRoute = createRoute({
+      getParentRoute: () => rootRoute,
+      path: '/',
+      component: () => {
+        return (
+          <React.Fragment>
+            <h1>Index</h1>
+            <Link to="/posts">Posts</Link>
+            <Link to="/posts/$postId/details" params={{ postId: 'id1' }}>
+              To first post
+            </Link>
+          </React.Fragment>
+        )
+      },
+    })
+
+    const layoutRoute = createRoute({
+      getParentRoute: () => rootRoute,
+      id: '_layout',
+      component: () => {
+        return (
+          <>
+            <h1>Layout</h1>
+            <Outlet />
+          </>
+        )
+      },
+    })
+
+    const PostsComponent = () => {
+      return (
+        <React.Fragment>
+          <h1>Posts</h1>
+          <Outlet />
+        </React.Fragment>
+      )
+    }
+
+    const postsRoute = createRoute({
+      getParentRoute: () => layoutRoute,
+      path: 'posts',
+      component: PostsComponent,
+    })
+
+    const PostComponent = () => {
+      const params = useParams({ strict: false })
+      return (
+        <React.Fragment>
+          <span>Params: {params.postId}</span>
+          <Outlet />
+        </React.Fragment>
+      )
+    }
+
+    const postRoute = createRoute({
+      getParentRoute: () => postsRoute,
+      path: '$postId',
+      component: PostComponent,
+    })
+
+    const DetailsComponent = () => {
+      return (
+        <>
+          <h1>Details!</h1>
+          <Link from="/posts/$postId" to="../$postId">
+            To Post
+          </Link>
+        </>
+      )
+    }
+
+    const detailsRoute = createRoute({
+      getParentRoute: () => postRoute,
+      path: 'details',
+      component: DetailsComponent,
+    })
+
+    const InformationComponent = () => {
+      return (
+        <React.Fragment>
+          <h1>Information</h1>
+        </React.Fragment>
+      )
+    }
+
+    const informationRoute = createRoute({
+      getParentRoute: () => postRoute,
+      path: 'info',
+      component: InformationComponent,
+    })
+
+    const router = createRouter({
+      routeTree: rootRoute.addChildren([
+        indexRoute,
+        layoutRoute.addChildren([
+          postsRoute.addChildren([
+            postRoute.addChildren([detailsRoute, informationRoute]),
+          ]),
+        ]),
+      ]),
+    })
+
+    render(<RouterProvider router={router} />)
+
+    const postsLink = await screen.findByRole('link', { name: 'To first post' })
+
+    expect(postsLink).toHaveAttribute('href', '/posts/id1/details')
+
+    fireEvent.click(postsLink)
+
+    expect(await screen.findByText('Params: id1')).toBeInTheDocument()
+
+    expect(window.location.pathname).toEqual('/posts/id1/details')
+
+    const postLink = await screen.findByRole('link', {
+      name: 'To Post',
+    })
+
+    expect(postLink).toHaveAttribute('href', '/posts/id1')
+
+    fireEvent.click(postLink)
+
+    expect(await screen.findByText('Posts')).toBeInTheDocument()
+
+    expect(window.location.pathname).toEqual('/posts/id1')
+  })
+
+  test('when navigating from /invoices to ./invoiceId and the current route is /posts/$postId/details', async () => {
+    const rootRoute = createRootRoute()
+
+    const indexRoute = createRoute({
+      getParentRoute: () => rootRoute,
+      path: '/',
+      component: () => {
+        return (
+          <React.Fragment>
+            <h1>Index</h1>
+            <Link to="/posts">Posts</Link>
+            <Link to="/posts/$postId/details" params={{ postId: 'id1' }}>
+              To first post
+            </Link>
+          </React.Fragment>
+        )
+      },
+    })
+
+    const layoutRoute = createRoute({
+      getParentRoute: () => rootRoute,
+      id: '_layout',
+      component: () => {
+        return (
+          <>
+            <h1>Layout</h1>
+            <Outlet />
+          </>
+        )
+      },
+    })
+
+    const PostsComponent = () => {
+      return (
+        <React.Fragment>
+          <h1>Posts</h1>
+          <Outlet />
+        </React.Fragment>
+      )
+    }
+
+    const postsRoute = createRoute({
+      getParentRoute: () => layoutRoute,
+      path: 'posts',
+      component: PostsComponent,
+    })
+
+    const PostComponent = () => {
+      const params = useParams({ strict: false })
+      return (
+        <React.Fragment>
+          <span>Params: {params.postId}</span>
+          <Outlet />
+        </React.Fragment>
+      )
+    }
+
+    const postRoute = createRoute({
+      getParentRoute: () => postsRoute,
+      path: '$postId',
+      component: PostComponent,
+    })
+
+    const DetailsComponent = () => {
+      return (
+        <>
+          <h1>Details!</h1>
+          <Link
+            from="/invoices"
+            to="./$invoiceId"
+            params={{ invoiceId: 'id1' }}
+          >
+            To Invoices
+          </Link>
+        </>
+      )
+    }
+
+    const detailsRoute = createRoute({
+      getParentRoute: () => postRoute,
+      path: 'details',
+      component: DetailsComponent,
+    })
+
+    const InformationComponent = () => {
+      return (
+        <React.Fragment>
+          <h1>Information</h1>
+        </React.Fragment>
+      )
+    }
+
+    const informationRoute = createRoute({
+      getParentRoute: () => postRoute,
+      path: 'info',
+      component: InformationComponent,
+    })
+
+    const invoicesRoute = createRoute({
+      getParentRoute: () => rootRoute,
+      path: 'invoices',
+      component: () => (
+        <>
+          <h1>Invoices!</h1>
+          <Outlet />
+        </>
+      ),
+    })
+
+    const InvoiceComponent = () => {
+      const params = useParams({ strict: false })
+      return (
+        <>
+          <span>invoiceId: {params.invoiceId}</span>
+        </>
+      )
+    }
+
+    const invoiceRoute = createRoute({
+      getParentRoute: () => invoicesRoute,
+      path: '$invoiceId',
+      component: InvoiceComponent,
+    })
+
+    const router = createRouter({
+      routeTree: rootRoute.addChildren([
+        indexRoute,
+        layoutRoute.addChildren([
+          invoicesRoute.addChildren([invoiceRoute]),
+          postsRoute.addChildren([
+            postRoute.addChildren([detailsRoute, informationRoute]),
+          ]),
+        ]),
+      ]),
+    })
+
+    render(<RouterProvider router={router} />)
+
+    const postsLink = await screen.findByRole('link', { name: 'To first post' })
+
+    expect(postsLink).toHaveAttribute('href', '/posts/id1/details')
+
+    fireEvent.click(postsLink)
+
+    expect(
+      await screen.findByText(
+        'Invariant failed: Could not find match for from: /invoices',
+      ),
+    ).toBeInTheDocument()
+  })
 })
 
 describe('createLink', () => {
diff --git a/packages/react-router/tests/useNavigate.test.tsx b/packages/react-router/tests/useNavigate.test.tsx
new file mode 100644
index 000000000..6c16e9b88
--- /dev/null
+++ b/packages/react-router/tests/useNavigate.test.tsx
@@ -0,0 +1,888 @@
+import React from 'react'
+import '@testing-library/jest-dom/vitest'
+import { afterEach, describe, expect, it, test, vi } from 'vitest'
+import { cleanup, fireEvent, render, screen } from '@testing-library/react'
+
+import {
+  createRootRoute,
+  createRoute,
+  createRouter,
+  useParams,
+  Outlet,
+  useNavigate,
+  RouterProvider,
+} from '../src'
+
+afterEach(() => {
+  window.history.replaceState(null, 'root', '/')
+  cleanup()
+})
+
+test('when navigating to /posts', async () => {
+  const rootRoute = createRootRoute()
+
+  const IndexComponent = () => {
+    const navigate = useNavigate()
+    return (
+      <React.Fragment>
+        <h1>Index</h1>
+        <button onClick={() => navigate({ to: '/' })}>Index</button>
+        <button onClick={() => navigate({ to: '/posts' })}>Posts</button>
+      </React.Fragment>
+    )
+  }
+
+  const indexRoute = createRoute({
+    getParentRoute: () => rootRoute,
+    path: '/',
+    component: IndexComponent,
+  })
+
+  const postsRoute = createRoute({
+    getParentRoute: () => rootRoute,
+    path: '/posts',
+    component: () => {
+      return (
+        <React.Fragment>
+          <h1>Posts</h1>
+        </React.Fragment>
+      )
+    },
+  })
+
+  const router = createRouter({
+    routeTree: rootRoute.addChildren([indexRoute, postsRoute]),
+  })
+
+  render(<RouterProvider router={router} />)
+
+  const postsButton = await screen.findByRole('button', { name: 'Posts' })
+
+  fireEvent.click(postsButton)
+
+  expect(
+    await screen.findByRole('heading', { name: 'Posts' }),
+  ).toBeInTheDocument()
+
+  expect(window.location.pathname).toBe('/posts')
+})
+
+test('when navigating from /posts to ./$postId', async () => {
+  const rootRoute = createRootRoute()
+  const IndexComponent = () => {
+    const navigate = useNavigate()
+    return (
+      <React.Fragment>
+        <h1>Index</h1>
+        <button onClick={() => navigate({ to: '/posts' })}>Posts</button>
+        <button
+          onClick={() =>
+            navigate({ to: '/posts/$postId', params: { postId: 'id1' } })
+          }
+        >
+          To first post
+        </button>
+      </React.Fragment>
+    )
+  }
+
+  const indexRoute = createRoute({
+    getParentRoute: () => rootRoute,
+    path: '/',
+    component: IndexComponent,
+  })
+
+  const PostsComponent = () => {
+    return (
+      <React.Fragment>
+        <h1>Posts</h1>
+        <Outlet />
+      </React.Fragment>
+    )
+  }
+
+  const postsRoute = createRoute({
+    getParentRoute: () => rootRoute,
+    path: 'posts',
+    component: PostsComponent,
+  })
+
+  const PostsIndexComponent = () => {
+    const navigate = useNavigate()
+    return (
+      <React.Fragment>
+        <h1>Posts Index</h1>
+        <button
+          onClick={() =>
+            navigate({
+              from: '/posts/',
+              to: './$postId',
+              params: { postId: 'id1' },
+            })
+          }
+        >
+          To the first post
+        </button>
+      </React.Fragment>
+    )
+  }
+
+  const postsIndexRoute = createRoute({
+    getParentRoute: () => postsRoute,
+    path: '/',
+    component: PostsIndexComponent,
+  })
+
+  const PostComponent = () => {
+    const params = useParams({ strict: false })
+    const navigate = useNavigate()
+    return (
+      <React.Fragment>
+        <span>Params: {params.postId}</span>
+        <button onClick={() => navigate({ to: '/' })}>Index</button>
+      </React.Fragment>
+    )
+  }
+
+  const postRoute = createRoute({
+    getParentRoute: () => postsRoute,
+    path: '$postId',
+    component: PostComponent,
+  })
+
+  const router = createRouter({
+    routeTree: rootRoute.addChildren([
+      indexRoute,
+      postsRoute.addChildren([postsIndexRoute, postRoute]),
+    ]),
+  })
+
+  render(<RouterProvider router={router} />)
+
+  const postsButton = await screen.findByRole('button', { name: 'Posts' })
+
+  fireEvent.click(postsButton)
+
+  expect(await screen.findByText('Posts Index')).toBeInTheDocument()
+
+  const postButton = await screen.findByRole('button', {
+    name: 'To the first post',
+  })
+
+  fireEvent.click(postButton)
+
+  expect(await screen.findByText('Params: id1')).toBeInTheDocument()
+
+  expect(window.location.pathname).toBe('/posts/id1')
+})
+
+test('when navigating from /posts to ../posts/$postId', async () => {
+  const rootRoute = createRootRoute()
+
+  const IndexComponent = () => {
+    const navigate = useNavigate()
+    return (
+      <React.Fragment>
+        <h1>Index</h1>
+        <button onClick={() => navigate({ to: '/posts' })}>Posts</button>
+        <button
+          onClick={() =>
+            navigate({ to: '/posts/$postId', params: { postId: 'id1' } })
+          }
+        >
+          To first post
+        </button>
+      </React.Fragment>
+    )
+  }
+
+  const indexRoute = createRoute({
+    getParentRoute: () => rootRoute,
+    path: '/',
+    component: IndexComponent,
+  })
+
+  const PostsComponent = () => {
+    return (
+      <React.Fragment>
+        <h1>Posts</h1>
+        <Outlet />
+      </React.Fragment>
+    )
+  }
+
+  const postsRoute = createRoute({
+    getParentRoute: () => rootRoute,
+    path: 'posts',
+    component: PostsComponent,
+  })
+
+  const PostsIndexComponent = () => {
+    const navigate = useNavigate()
+    return (
+      <React.Fragment>
+        <h1>Posts Index</h1>
+        <button
+          onClick={() =>
+            navigate({
+              from: '/posts/',
+              to: '../posts/$postId',
+              params: { postId: 'id1' },
+            })
+          }
+        >
+          To the first post
+        </button>
+      </React.Fragment>
+    )
+  }
+
+  const postsIndexRoute = createRoute({
+    getParentRoute: () => postsRoute,
+    path: '/',
+    component: PostsIndexComponent,
+  })
+
+  const PostComponent = () => {
+    const navigate = useNavigate()
+    const params = useParams({ strict: false })
+    return (
+      <React.Fragment>
+        <span>Params: {params.postId}</span>
+        <button onClick={() => navigate({ to: '/' })}>Index</button>
+      </React.Fragment>
+    )
+  }
+
+  const postRoute = createRoute({
+    getParentRoute: () => postsRoute,
+    path: '$postId',
+    component: PostComponent,
+  })
+
+  const router = createRouter({
+    routeTree: rootRoute.addChildren([
+      indexRoute,
+      postsRoute.addChildren([postsIndexRoute, postRoute]),
+    ]),
+  })
+
+  render(<RouterProvider router={router} />)
+
+  const postsButton = await screen.findByRole('button', { name: 'Posts' })
+
+  fireEvent.click(postsButton)
+
+  expect(await screen.findByText('Posts Index')).toBeInTheDocument()
+
+  const postButton = await screen.findByRole('button', {
+    name: 'To the first post',
+  })
+
+  fireEvent.click(postButton)
+
+  expect(await screen.findByText('Params: id1')).toBeInTheDocument()
+})
+
+test('when navigating from /posts/$postId to /posts/$postId/info and the current route is /posts/$postId/details', async () => {
+  const rootRoute = createRootRoute()
+
+  const IndexComponent = () => {
+    const navigate = useNavigate()
+    return (
+      <React.Fragment>
+        <h1>Index</h1>
+        <button onClick={() => navigate({ to: '/posts' })}>Posts</button>
+        <button
+          onClick={() =>
+            navigate({
+              to: '/posts/$postId/details',
+              params: { postId: 'id1' },
+            })
+          }
+        >
+          To first post
+        </button>
+      </React.Fragment>
+    )
+  }
+
+  const indexRoute = createRoute({
+    getParentRoute: () => rootRoute,
+    path: '/',
+    component: IndexComponent,
+  })
+
+  const layoutRoute = createRoute({
+    getParentRoute: () => rootRoute,
+    id: '_layout',
+    component: () => {
+      return (
+        <>
+          <h1>Layout</h1>
+          <Outlet />
+        </>
+      )
+    },
+  })
+
+  const PostsComponent = () => {
+    return (
+      <React.Fragment>
+        <h1>Posts</h1>
+        <Outlet />
+      </React.Fragment>
+    )
+  }
+
+  const postsRoute = createRoute({
+    getParentRoute: () => layoutRoute,
+    path: 'posts',
+    component: PostsComponent,
+  })
+
+  const PostComponent = () => {
+    const params = useParams({ strict: false })
+    return (
+      <React.Fragment>
+        <span>Params: {params.postId}</span>
+        <Outlet />
+      </React.Fragment>
+    )
+  }
+
+  const postRoute = createRoute({
+    getParentRoute: () => postsRoute,
+    path: '$postId',
+    component: PostComponent,
+  })
+
+  const DetailsComponent = () => {
+    const navigate = useNavigate()
+    return (
+      <>
+        <h1>Details!</h1>
+        <button
+          onClick={() =>
+            navigate({ from: '/posts/$postId', to: '/posts/$postId/info' })
+          }
+        >
+          To Information
+        </button>
+      </>
+    )
+  }
+
+  const detailsRoute = createRoute({
+    getParentRoute: () => postRoute,
+    path: 'details',
+    component: DetailsComponent,
+  })
+
+  const InformationComponent = () => {
+    return (
+      <React.Fragment>
+        <h1>Information</h1>
+      </React.Fragment>
+    )
+  }
+
+  const informationRoute = createRoute({
+    getParentRoute: () => postRoute,
+    path: 'info',
+    component: InformationComponent,
+  })
+
+  const router = createRouter({
+    routeTree: rootRoute.addChildren([
+      indexRoute,
+      layoutRoute.addChildren([
+        postsRoute.addChildren([
+          postRoute.addChildren([detailsRoute, informationRoute]),
+        ]),
+      ]),
+    ]),
+  })
+
+  render(<RouterProvider router={router} />)
+
+  const postsButton = await screen.findByRole('button', {
+    name: 'To first post',
+  })
+
+  fireEvent.click(postsButton)
+
+  expect(await screen.findByText('Params: id1')).toBeInTheDocument()
+
+  expect(window.location.pathname).toEqual('/posts/id1/details')
+
+  const informationButton = await screen.findByRole('button', {
+    name: 'To Information',
+  })
+
+  fireEvent.click(informationButton)
+
+  expect(await screen.findByText('Information')).toBeInTheDocument()
+
+  expect(window.location.pathname).toEqual('/posts/id1/info')
+
+  expect(await screen.findByText('Params: id1'))
+})
+
+test('when navigating from /posts/$postId to ./info and the current route is /posts/$postId/details', async () => {
+  const rootRoute = createRootRoute()
+
+  const IndexComponent = () => {
+    const navigate = useNavigate()
+    return (
+      <React.Fragment>
+        <h1>Index</h1>
+        <button onClick={() => navigate({ to: '/posts' })}>Posts</button>
+        <button
+          onClick={() =>
+            navigate({
+              to: '/posts/$postId/details',
+              params: { postId: 'id1' },
+            })
+          }
+        >
+          To first post
+        </button>
+      </React.Fragment>
+    )
+  }
+
+  const indexRoute = createRoute({
+    getParentRoute: () => rootRoute,
+    path: '/',
+    component: IndexComponent,
+  })
+
+  const layoutRoute = createRoute({
+    getParentRoute: () => rootRoute,
+    id: '_layout',
+    component: () => {
+      return (
+        <>
+          <h1>Layout</h1>
+          <Outlet />
+        </>
+      )
+    },
+  })
+
+  const PostsComponent = () => {
+    return (
+      <React.Fragment>
+        <h1>Posts</h1>
+        <Outlet />
+      </React.Fragment>
+    )
+  }
+
+  const postsRoute = createRoute({
+    getParentRoute: () => layoutRoute,
+    path: 'posts',
+    component: PostsComponent,
+  })
+
+  const PostComponent = () => {
+    const params = useParams({ strict: false })
+    return (
+      <React.Fragment>
+        <span>Params: {params.postId}</span>
+        <Outlet />
+      </React.Fragment>
+    )
+  }
+
+  const postRoute = createRoute({
+    getParentRoute: () => postsRoute,
+    path: '$postId',
+    component: PostComponent,
+  })
+
+  const DetailsComponent = () => {
+    const navigate = useNavigate()
+    return (
+      <>
+        <h1>Details!</h1>
+        <button
+          onClick={() => navigate({ from: '/posts/$postId', to: './info' })}
+        >
+          To Information
+        </button>
+      </>
+    )
+  }
+
+  const detailsRoute = createRoute({
+    getParentRoute: () => postRoute,
+    path: 'details',
+    component: DetailsComponent,
+  })
+
+  const InformationComponent = () => {
+    return (
+      <React.Fragment>
+        <h1>Information</h1>
+      </React.Fragment>
+    )
+  }
+
+  const informationRoute = createRoute({
+    getParentRoute: () => postRoute,
+    path: 'info',
+    component: InformationComponent,
+  })
+
+  const router = createRouter({
+    routeTree: rootRoute.addChildren([
+      indexRoute,
+      layoutRoute.addChildren([
+        postsRoute.addChildren([
+          postRoute.addChildren([detailsRoute, informationRoute]),
+        ]),
+      ]),
+    ]),
+  })
+
+  render(<RouterProvider router={router} />)
+
+  const postsButton = await screen.findByRole('button', {
+    name: 'To first post',
+  })
+
+  fireEvent.click(postsButton)
+
+  expect(await screen.findByText('Params: id1')).toBeInTheDocument()
+
+  expect(window.location.pathname).toEqual('/posts/id1/details')
+
+  const informationButton = await screen.findByRole('button', {
+    name: 'To Information',
+  })
+
+  fireEvent.click(informationButton)
+
+  expect(await screen.findByText('Information')).toBeInTheDocument()
+
+  expect(window.location.pathname).toEqual('/posts/id1/info')
+
+  expect(await screen.findByText('Params: id1'))
+})
+
+test('when navigating from /posts/$postId to ../$postId and the current route is /posts/$postId/details', async () => {
+  const rootRoute = createRootRoute()
+
+  const IndexComponent = () => {
+    const navigate = useNavigate()
+    return (
+      <React.Fragment>
+        <h1>Index</h1>
+        <button onClick={() => navigate({ to: '/posts' })}>Posts</button>
+        <button
+          onClick={() =>
+            navigate({
+              to: '/posts/$postId/details',
+              params: { postId: 'id1' },
+            })
+          }
+        >
+          To first post
+        </button>
+      </React.Fragment>
+    )
+  }
+
+  const indexRoute = createRoute({
+    getParentRoute: () => rootRoute,
+    path: '/',
+    component: IndexComponent,
+  })
+
+  const layoutRoute = createRoute({
+    getParentRoute: () => rootRoute,
+    id: '_layout',
+    component: () => {
+      return (
+        <>
+          <h1>Layout</h1>
+          <Outlet />
+        </>
+      )
+    },
+  })
+
+  const PostsComponent = () => {
+    return (
+      <React.Fragment>
+        <h1>Posts</h1>
+        <Outlet />
+      </React.Fragment>
+    )
+  }
+
+  const postsRoute = createRoute({
+    getParentRoute: () => layoutRoute,
+    path: 'posts',
+    component: PostsComponent,
+  })
+
+  const PostComponent = () => {
+    const params = useParams({ strict: false })
+    return (
+      <React.Fragment>
+        <span>Params: {params.postId}</span>
+        <Outlet />
+      </React.Fragment>
+    )
+  }
+
+  const postRoute = createRoute({
+    getParentRoute: () => postsRoute,
+    path: '$postId',
+    component: PostComponent,
+  })
+
+  const DetailsComponent = () => {
+    const navigate = useNavigate()
+    return (
+      <>
+        <h1>Details!</h1>
+        <button
+          onClick={() => navigate({ from: '/posts/$postId', to: '../$postId' })}
+        >
+          To Post
+        </button>
+      </>
+    )
+  }
+
+  const detailsRoute = createRoute({
+    getParentRoute: () => postRoute,
+    path: 'details',
+    component: DetailsComponent,
+  })
+
+  const InformationComponent = () => {
+    return (
+      <React.Fragment>
+        <h1>Information</h1>
+      </React.Fragment>
+    )
+  }
+
+  const informationRoute = createRoute({
+    getParentRoute: () => postRoute,
+    path: 'info',
+    component: InformationComponent,
+  })
+
+  const router = createRouter({
+    routeTree: rootRoute.addChildren([
+      indexRoute,
+      layoutRoute.addChildren([
+        postsRoute.addChildren([
+          postRoute.addChildren([detailsRoute, informationRoute]),
+        ]),
+      ]),
+    ]),
+  })
+
+  render(<RouterProvider router={router} />)
+
+  const postsButton = await screen.findByRole('button', {
+    name: 'To first post',
+  })
+
+  fireEvent.click(postsButton)
+
+  expect(await screen.findByText('Params: id1')).toBeInTheDocument()
+
+  expect(window.location.pathname).toEqual('/posts/id1/details')
+
+  const postButton = await screen.findByRole('button', {
+    name: 'To Post',
+  })
+
+  fireEvent.click(postButton)
+
+  expect(await screen.findByText('Posts')).toBeInTheDocument()
+
+  expect(window.location.pathname).toEqual('/posts/id1')
+})
+
+test('when navigating from /invoices to ./invoiceId and the current route is /posts/$postId/details', async () => {
+  const rootRoute = createRootRoute()
+
+  const IndexComponent = () => {
+    const navigate = useNavigate()
+    return (
+      <React.Fragment>
+        <h1>Index</h1>
+        <button onClick={() => navigate({ to: '/posts' })}>Posts</button>
+        <button
+          onClick={() =>
+            navigate({
+              to: '/posts/$postId/details',
+              params: { postId: 'id1' },
+            })
+          }
+        >
+          To first post
+        </button>
+      </React.Fragment>
+    )
+  }
+
+  const indexRoute = createRoute({
+    getParentRoute: () => rootRoute,
+    path: '/',
+    component: IndexComponent,
+  })
+
+  const layoutRoute = createRoute({
+    getParentRoute: () => rootRoute,
+    id: '_layout',
+    component: () => {
+      return (
+        <>
+          <h1>Layout</h1>
+          <Outlet />
+        </>
+      )
+    },
+  })
+
+  const PostsComponent = () => {
+    return (
+      <React.Fragment>
+        <h1>Posts</h1>
+        <Outlet />
+      </React.Fragment>
+    )
+  }
+
+  const postsRoute = createRoute({
+    getParentRoute: () => layoutRoute,
+    path: 'posts',
+    component: PostsComponent,
+  })
+
+  const PostComponent = () => {
+    const params = useParams({ strict: false })
+    return (
+      <React.Fragment>
+        <span>Params: {params.postId}</span>
+        <Outlet />
+      </React.Fragment>
+    )
+  }
+
+  const postRoute = createRoute({
+    getParentRoute: () => postsRoute,
+    path: '$postId',
+    component: PostComponent,
+  })
+
+  const DetailsComponent = () => {
+    const navigate = useNavigate()
+    const [error, setError] = React.useState<unknown>()
+    return (
+      <>
+        <h1>Details!</h1>
+        <button
+          onClick={() => {
+            try {
+              navigate({
+                from: '/invoices',
+                to: './$invoiceId',
+                params: { invoiceId: 'id1' },
+              })
+            } catch (e) {
+              setError(e)
+            }
+          }}
+        >
+          To Invoices
+        </button>
+        <span>Something went wrong!</span>
+      </>
+    )
+  }
+
+  const detailsRoute = createRoute({
+    getParentRoute: () => postRoute,
+    path: 'details',
+    component: DetailsComponent,
+  })
+
+  const InformationComponent = () => {
+    return (
+      <React.Fragment>
+        <h1>Information</h1>
+      </React.Fragment>
+    )
+  }
+
+  const informationRoute = createRoute({
+    getParentRoute: () => postRoute,
+    path: 'info',
+    component: InformationComponent,
+  })
+
+  const invoicesRoute = createRoute({
+    getParentRoute: () => rootRoute,
+    path: 'invoices',
+    component: () => (
+      <>
+        <h1>Invoices!</h1>
+        <Outlet />
+      </>
+    ),
+  })
+
+  const InvoiceComponent = () => {
+    const params = useParams({ strict: false })
+    return (
+      <>
+        <span>invoiceId: {params.invoiceId}</span>
+      </>
+    )
+  }
+
+  const invoiceRoute = createRoute({
+    getParentRoute: () => invoicesRoute,
+    path: '$invoiceId',
+    component: InvoiceComponent,
+  })
+
+  const router = createRouter({
+    routeTree: rootRoute.addChildren([
+      indexRoute,
+      layoutRoute.addChildren([
+        invoicesRoute.addChildren([invoiceRoute]),
+        postsRoute.addChildren([
+          postRoute.addChildren([detailsRoute, informationRoute]),
+        ]),
+      ]),
+    ]),
+  })
+
+  render(<RouterProvider router={router} />)
+
+  const postsButton = await screen.findByRole('button', {
+    name: 'To first post',
+  })
+
+  fireEvent.click(postsButton)
+
+  const invoicesButton = await screen.findByRole('button', {
+    name: 'To Invoices',
+  })
+
+  fireEvent.click(invoicesButton)
+
+  expect(await screen.findByText('Something went wrong!')).toBeInTheDocument()
+})