Skip to content

Commit 90a66e4

Browse files
authored
feat: better typing for route.pathname (#89)
1 parent 20f5b50 commit 90a66e4

File tree

3 files changed

+52
-21
lines changed

3 files changed

+52
-21
lines changed

.changeset/cuddly-ads-lay.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'sv-router': patch
3+
---
4+
5+
Better typing for route.pathname

src/index.d.ts

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ export type RouterApi<T extends Routes> = {
146146
*/
147147
params: AllParams<T>;
148148
/** The reactive pathname of the URL. */
149-
pathname: Path<T>;
149+
pathname: (Path<T, true> & {}) | (string & {});
150150
/** The reactive query string part of the URL. */
151151
search: string;
152152
/** The reactive history state that can be passed to the `navigate` function. */
@@ -156,8 +156,8 @@ export type RouterApi<T extends Routes> = {
156156
};
157157
};
158158

159-
export type Path<T extends Routes> = RemoveParenthesis<
160-
RemoveLastSlash<RecursiveKeys<StripNonRoutes<T>>>
159+
export type Path<T extends Routes, AnyParam extends boolean = false> = RemoveParenthesis<
160+
RemoveLastSlash<RecursiveKeys<StripNonRoutes<T>, '', AnyParam>>
161161
>;
162162

163163
export type ConstructPathArgs<T extends string> =
@@ -167,9 +167,13 @@ export type IsActiveArgs<T extends string> =
167167
PathParams<T> extends never ? [T] : [T] | [T, PathParams<T>];
168168

169169
export type PathParams<T extends string> =
170-
ExtractParams<T> extends never ? never : Record<ExtractParams<T>, string>;
170+
ExtractParams<RemoveParenthesis<T>> extends never
171+
? never
172+
: Record<ExtractParams<RemoveParenthesis<T>>, string>;
171173

172-
export type AllParams<T extends Routes> = Partial<Record<ExtractParams<RecursiveKeys<T>>, string>>;
174+
export type AllParams<T extends Routes> = Partial<
175+
Record<ExtractParams<RemoveParenthesis<RecursiveKeys<T>>>, string>
176+
>;
173177

174178
export type NavigateOptions =
175179
| {
@@ -207,14 +211,28 @@ type StripNonRoutes<T extends Routes> = {
207211
: K]: T[K] extends Routes ? StripNonRoutes<T[K]> : T[K];
208212
};
209213

210-
type RecursiveKeys<T extends Routes, Prefix extends string = ''> = {
214+
type RecursiveKeys<
215+
T extends Routes,
216+
Prefix extends string = '',
217+
AnyParam extends boolean = false,
218+
> = {
211219
[K in keyof T]: K extends string
212220
? T[K] extends Routes
213-
? RecursiveKeys<T[K], `${Prefix}${K}`>
214-
: `${Prefix}${K}`
221+
? RecursiveKeys<
222+
T[K],
223+
`${Prefix}${AnyParam extends true ? ReplaceParamWithString<K> : K}`,
224+
AnyParam
225+
>
226+
: `${Prefix}${AnyParam extends true ? ReplaceParamWithString<K> : K}`
215227
: never;
216228
}[keyof T];
217229

230+
type ReplaceParamWithString<T extends string> = T extends `/:${string}`
231+
? `/${string}`
232+
: T extends `/(:${string})`
233+
? `/${string}`
234+
: T;
235+
218236
type RemoveLastSlash<T extends string> = T extends '/' ? T : T extends `${infer R}/` ? R : T;
219237

220238
type RemoveParenthesis<T extends string> = T extends `${infer A}(${infer B})${infer C}`
@@ -223,14 +241,10 @@ type RemoveParenthesis<T extends string> = T extends `${infer A}(${infer B})${in
223241

224242
type ExtractParams<T extends string> = T extends `${string}:${infer Param}/${infer Rest}`
225243
? Param | ExtractParams<`/${Rest}`>
226-
: T extends `${string}(:${infer Param})`
244+
: T extends `${string}:${infer Param}`
227245
? Param
228-
: T extends `${string}:${infer Param}`
229-
? Param
230-
: T extends `${string}(*${infer Param})`
231-
? Param
232-
: T extends `${string}*${infer Param}`
233-
? Param extends ''
234-
? never
235-
: Param
236-
: never;
246+
: T extends `${string}*${infer Param}`
247+
? Param extends ''
248+
? never
249+
: Param
250+
: never;

tests/test-types.d.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@ type TestRoutes = {
2626

2727
// Path
2828

29-
type test_path = Expect<Equal<test_path_result, test_path_expected>>;
30-
type test_path_result = Path<TestRoutes>;
31-
type test_path_expected =
29+
type test_path_0 = Expect<Equal<test_path_result_0, test_path_expected_0>>;
30+
type test_path_result_0 = Path<TestRoutes>;
31+
type test_path_expected_0 =
3232
| '/'
3333
| '/about'
3434
| '/contact/nested'
@@ -38,6 +38,18 @@ type test_path_expected =
3838
| `/posts/:id`
3939
| `/posts/:id/:commentId`;
4040

41+
type test_path_1 = Expect<Equal<test_path_result_1, test_path_expected_1>>;
42+
type test_path_result_1 = Path<TestRoutes, true>;
43+
type test_path_expected_1 =
44+
| '/'
45+
| '/about'
46+
| '/contact/nested'
47+
| '/posts'
48+
| '/posts/static'
49+
| '/posts/nolayout'
50+
| `/posts/${string}`
51+
| `/posts/${string}/${string}`;
52+
4153
// PathParams
4254

4355
type test_path_params_0 = Expect<Equal<test_path_params_result_0, test_path_params_expected_0>>;

0 commit comments

Comments
 (0)