[Router/FS] Trailing slash in routePathFromFile breaks TypeScript inference for nested paths in `paths` proxy
Maintainer antworten meist innerhalb von 1 Tag
Dieses Issue hat noch niemand übernommen.
Bewertung
- Schwierigkeit
- 2/5
- Geschätzter Aufwand
- 1-3 Stunden
- Anfängerfreundlichkeit
- 85/100
- Issue-Typ
- Bug
- Klarheit
- Klar beschrieben
- Aktivitätsstatus
- Aktiv
- Tech-Stack
- typescript
- Bereich
- web-dev
Rechercherichtung
Beginne in filesystem-routing/dist/convention.js bei routePathFromFile und reproduziere den generierten Pfad anhand der Routenstruktur posts/[id]/index.tsx. Überprüfe die generierte Deklaration und die TypeScript-Inferenz von paths.posts(id).edit(). Erledigt ist die Aufgabe, wenn Index-Routen /posts/:id ohne abschließenden Schrägstrich ausgeben und der Aufruf der verschachtelten paths erfolgreich kompiliert.
Vom Indexierungsmodell aus dem Issue-Text verfasst.
Beschreibung
Describe the bug
When using file-system routing with index.tsx inside dynamic route folders, filesystem-routing produces paths with an unintended trailing slash (e.g. /posts/:id/ instead of /posts/:id).
This trailing slash causes @solidjs/router's type generator (SegmentsOf) to split the path into ["posts", ":id", ""] with a phantom empty segment "" at the end. As a result:
- When calling a nested subpath on the
pathsproxy:paths.posts(id).edit(), TypeScript selects the first matching overload signature (which terminated atPathEnddue to the empty segment) and throws:error TS2339: Property 'edit' does not exist on type 'PathEnd<DefaultSearchTypes, { id: string; }>'. - Meanwhile, at runtime,
createPathsProxyworks completely fine and outputs"/posts/1/edit".
Your Example Website or App
Blank
Steps to Reproduce the Bug or Issue
Step 1: In a project using @solidjs/router/fs and filesystem-routing, create the following route structure:
src/routes/
└── posts/
├── [id]/
│ ├── index.tsx # Post detail
│ └── edit.tsx # Post edit
└── index.tsx # Posts list
Step 2: Generate the route types using fileRoutes({ types: true }).
Notice in the generated declaration, the route path is emitted with a trailing slash:
path: "/posts/:id/"
Step 3: Attempt to use the typed paths proxy in any component:
import { paths } from "~/router";
// ❌ TypeScript Error: Property 'edit' does not exist on type 'PathEnd<...>'
paths.posts(1).edit();
Minimal TypeScript reproduction (no file system needed):
import { createRouter, defineRoutes } from "@solidjs/router";
const Router = createRouter({
routes: defineRoutes([
{ path: "/posts/:id/" }, // generated from [id]/index.tsx
{ path: "/posts/:id/edit" } // generated from [id]/edit.tsx
])
});
// ❌ TypeScript Error: Property 'edit' does not exist on type 'PathEnd<...>'
Router.paths.posts(1).edit();
// ✅ If the trailing slash is removed, it compiles cleanly:
const FixedRouter = createRouter({
routes: defineRoutes([
{ path: "/posts/:id" },
{ path: "/posts/:id/edit" }
])
});
FixedRouter.paths.posts(1).edit(); // OK!
Expected behavior
filesystem-routingshould emit/posts/:id(without trailing slash) forposts/[id]/index.tsx.paths.posts(id).edit()should be accepted by TypeScript and infer the full path"/posts/1/edit"without type errors.
Screenshots or Videos
No response
Platform
- OS: Windows 10
- Node: 24
- SolidJS:
2.0.0-rc.6 @solidjs/router:2.0.0-next.34(latest)filesystem-routing:0.4.0(latest)- TypeScript:
5.9.2
Additional context
The bug originates in filesystem-routing/dist/convention.js:
export function routePathFromFile(routeFile) {
const routePath = routeFile
.slice(1)
.replace(/(^|\/)index$/, "$1") // ⚠️ BUG: Replaces "/index" with "$1" ("/") instead of stripping the slash
.replace(/\[([^/]+)\]/g, ...);
return routePath?.length > 0 ? `/${routePath}` : "/";
}
Replacing /(^|\/)index$/ with $1 preserves the preceding slash, turning posts/[id]/index into posts/[id]/.
Proposed fix:
- .replace(/(^|\/)index$/, "$1")
+ .replace(/\/index$/, "")
Or normalize trailing slashes on all non-root routes:
return routePath?.length > 0 ? `/${routePath.replace(/\/+$/, "")}` : "/";
- Vorherrschende Sprache
- TypeScript
- Sterne
- 1.3k
- Forks
- 183
- Ø Merge
- 14 Std. 35 Min.
- Gemergte PRs (30 T.)
- 52
Entwicklungsumgebung
- Kein Dockerfile und keine Docker-Compose-Datei
- Keine Pull-Request-Vorlage
- Beitragsleitfaden lesen
Erste Schritte
- Lesen Sie das ganze Issue und danach den Beitragsleitfaden des Projekts.
- Schreiben Sie ins Issue, dass Sie es übernehmen — das erspart doppelte Arbeit.
- Forken Sie das Repository und arbeiten Sie in einem Branch.
- Öffnen Sie einen Pull Request, der die Issue-Nummer nennt.
Mehr aus solidjs/solid-router
-
Schwierigkeit 4/5 1-2 Tage Anfängerfreundlichkeit 54/100
solidjs/solid-router#687 ·
Maintainer antworten meist innerhalb von 1 Tag
-
<A> costs ~6us of server CPU per instance during SSR (20x a plain <a>), mostly mergeProps/splitPropsEvtl. vergeben @birkskyum hat das vor 70 Tagen übernommen. Offen1.x
Schwierigkeit 4/5 3-5 Tage Anfängerfreundlichkeit 55/100
solidjs/solid-router#583 ·
Maintainer antworten meist innerhalb von 1 Tag
-
1.x enhancement
Schwierigkeit 3/5 1-2 Tage Anfängerfreundlichkeit 38/100
solidjs/solid-router#518 · 2 Kommentare ·
Maintainer antworten meist innerhalb von 1 Tag
-
Schwierigkeit 4/5 3-5 Tage Anfängerfreundlichkeit 35/100
solidjs/solid-router#482 · 2 Kommentare ·
Maintainer antworten meist innerhalb von 1 Tag
-
enhancement
Schwierigkeit 4/5 3-5 Tage Anfängerfreundlichkeit 25/100
solidjs/solid-router#459 · 2 Kommentare ·
Maintainer antworten meist innerhalb von 1 Tag
Alle Issues in solidjs/solid-router
Ähnliche Issues
-
"Contains" page watch never matches when its text has a trailing spaceEvtl. vergeben @RaphaelFakhri hat das heute übernommen. Offen
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 77/100
CopilotKit/openmuse#184 ·
Maintainer antworten meist innerhalb von 1 Tag
-
Schwierigkeit 1/5 Unter einer Stunde Anfängerfreundlichkeit 88/100
Maintainer antworten meist innerhalb von 1 Tag
-
bug
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 67/100
bootstrap-vue-next/bootstrap-vue-next#3357 ·
Maintainer antworten meist innerhalb von 1 Tag
-
[quality] tide.ts: six mutation survivors in the merge-queue gate, draft refusal, fork-403 workflow-file diagnosis and getPull's fork flag are unpinned by any testEvtl. vergeben @hivecommons-hive hat das heute übernommen. Offenagent/quality needs-kind stage/040-covered-by-pr testing
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 68/100
cncf/prow-github-actions#517 · 1 Kommentar ·
Maintainer antworten meist innerhalb von 2 Tagen
-
Unsampled pageload span is profiled when profileLifecycle is 'trace' (browser UI profiling)Evtl. vergeben @Jxxunnn hat das heute übernommen. OffenBrowser Waiting for: Product Owner
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 82/100
getsentry/sentry-javascript#25497 · 1 Kommentar ·
Maintainer antworten meist innerhalb von 1 Tag