Skip to content

Commit bd82f71

Browse files
committed
refactor(router): simplify types for path param detection
1 parent f1aa2db commit bd82f71

File tree

2 files changed

+49
-38
lines changed

2 files changed

+49
-38
lines changed

docs/utils/generate-path.md

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,30 @@ title: generatePath
88
<summary>Type declaration</summary>
99

1010
```tsx
11-
type PathParams<Path extends string> =
12-
Path extends `:${infer Param}/${infer Rest}`
13-
? Param | PathParams<Rest>
14-
: Path extends `:${infer Param}`
15-
? Param
16-
: Path extends `${any}:${infer Param}`
17-
? PathParams<`:${Param}`>
18-
: Path extends `${any}/*`
19-
? "*"
20-
: Path extends "*"
21-
? "*"
22-
: never;
11+
// Recursive helper for finding path parameters in the absence of wildcards
12+
type _PathParam<Path extends string> =
13+
// split path into individual path segments
14+
Path extends `${infer L}/${infer R}` ? _PathParam<L> | _PathParam<R> :
15+
// find params after `:`
16+
Path extends `${string}:${infer Param}` ? Param :
17+
// otherwise, there aren't any params present
18+
never
19+
20+
/**
21+
* Examples:
22+
* "/a/b/*" -> "/*"
23+
* ":a" -> "a"
24+
* "/a/:b" -> "b"
25+
* "/:a/:b" -> "a" | "b"
26+
*/
27+
type PathParam<Path extends string> =
28+
// check if path is just a wildcard
29+
Path extends "*" ? "*" :
30+
// look for wildcard at the end of the path
31+
Path extends `${infer Rest}/*` ? "*" | _PathParam<Rest> :
32+
// look for params in the absence of wildcards
33+
_PathParam<Path>
34+
2335

2436
declare function generatePath<Path extends string>(
2537
path: Path,

packages/router/utils.ts

Lines changed: 25 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -161,40 +161,39 @@ export interface DataRouteObject extends RouteObject {
161161
id: string;
162162
}
163163

164-
type Star = "*";
164+
// Recursive helper for finding path parameters in the absence of wildcards
165+
type _PathParam<Path extends string> =
166+
// split path into individual path segments
167+
Path extends `${infer L}/${infer R}` ? _PathParam<L> | _PathParam<R> :
168+
// find params after `:`
169+
Path extends `${string}:${infer Param}` ? Param :
170+
// otherwise, there aren't any params present
171+
never
172+
165173
/**
166-
* @private
167-
* Return string union from path string.
168-
* @example
169-
* PathParam<"/path/:a/:b"> // "a" | "b"
170-
* PathParam<"/path/:a/:b/*"> // "a" | "b" | "*"
174+
* Examples:
175+
* "/a/b/*" -> "*"
176+
* ":a" -> "a"
177+
* "/a/:b" -> "b"
178+
* "/a/blahblahblah:b" -> "b"
179+
* "/:a/:b" -> "a" | "b"
180+
* "/:a/b/:c/*" -> "a" | "c" | "*"
171181
*/
172182
type PathParam<Path extends string> =
173-
// Check path string starts with slash and a param string.
174-
Path extends `:${infer Param}/${infer Rest}`
175-
? Param | PathParam<Rest>
176-
: // Check path string is a param string.
177-
Path extends `:${infer Param}`
178-
? Param
179-
: // Check path string ends with slash and a param string.
180-
Path extends `${any}/:${infer Param}`
181-
? PathParam<`:${Param}`>
182-
: // Check path string ends with slash and a star.
183-
Path extends `${any}/${Star}`
184-
? Star
185-
: // Check string is star.
186-
Path extends Star
187-
? Star
188-
: never;
183+
// check if path is just a wildcard
184+
Path extends "*" ? "*" :
185+
// look for wildcard at the end of the path
186+
Path extends `${infer Rest}/*` ? "*" | _PathParam<Rest> :
187+
// look for params in the absence of wildcards
188+
_PathParam<Path>
189189

190190
// Attempt to parse the given string segment. If it fails, then just return the
191191
// plain string type as a default fallback. Otherwise return the union of the
192192
// parsed string literals that were referenced as dynamic segments in the route.
193-
export type ParamParseKey<Segment extends string> = [
193+
export type ParamParseKey<Segment extends string> =
194+
// if could not find path params, fallback to `string`
195+
[PathParam<Segment>] extends [never] ? string :
194196
PathParam<Segment>
195-
] extends [never]
196-
? PathParam<Segment>
197-
: string;
198197

199198
/**
200199
* The parameters that were parsed from the URL path.

0 commit comments

Comments
 (0)