diff --git a/src/types/routeMethods.test-d.ts b/src/types/routeMethods.test-d.ts index 52453df9..5c83829c 100644 --- a/src/types/routeMethods.test-d.ts +++ b/src/types/routeMethods.test-d.ts @@ -405,4 +405,23 @@ test('public parent routes have correct type for parameters', () => { param2: string, param3: boolean, }]>() +}) + +test('param names must be alphanumeric', () => { + const routes = [ + { + name: 'foo', + path: '/:param1-:param2/:param3_:param4', + component, + }, + ] as const satisfies Routes + + const router = createRouter(routes) + + expectTypeOf(router.routes.foo).parameters.toEqualTypeOf<[{ + param1: string, + param2: string, + param3: string, + param4: string, + }]>() }) \ No newline at end of file diff --git a/src/types/routeMethods.ts b/src/types/routeMethods.ts index eb75a98b..19b606fd 100644 --- a/src/types/routeMethods.ts +++ b/src/types/routeMethods.ts @@ -1,6 +1,6 @@ import { Param, ParamGetSet, ParamGetter } from '@/types/params' import { Route, Routes } from '@/types/routes' -import { Identity, IsAny, IsEmptyObject, TupleCanBeAllUndefined, UnionToIntersection } from '@/types/utilities' +import { Identity, IsAny, IsEmptyObject, ReplaceAll, TupleCanBeAllUndefined, UnionToIntersection } from '@/types/utilities' import { Path } from '@/utilities/path' export type RouteMethod< @@ -58,17 +58,23 @@ export type ExtractRouteMethodParams = T extends RouteMethod export type ExtractParamsFromPath< TPath extends Route['path'] > = TPath extends Path - ? ExtractParamsFromPathString + ? ExtractParamsFromPathString, TPath['params']> : TPath extends string - ? ExtractParamsFromPathString + ? ExtractParamsFromPathString> : never +type ParamEnd = '/' + +type UnifyParamEnds< + TPath extends string +> = ReplaceAll, '_', ParamEnd> + export type ExtractParamsFromPathString< TPath extends string, TParams extends Record = Record -> = TPath extends `${infer Path}/` +> = TPath extends `${infer Path}${ParamEnd}` ? ExtractParamsFromPathString - : TPath extends `${string}:${infer Param}/${infer Rest}` + : TPath extends `${string}:${infer Param}${ParamEnd}${infer Rest}` ? MergeParams<{ [P in ExtractParamName]: ExtractPathParamType }, ExtractParamsFromPathString> : TPath extends `${string}:${infer Param}` ? { [P in ExtractParamName]: ExtractPathParamType } diff --git a/src/types/utilities.ts b/src/types/utilities.ts index 154b9640..0b581b94 100644 --- a/src/types/utilities.ts +++ b/src/types/utilities.ts @@ -36,4 +36,13 @@ export type UnionToIntersection = ( ? Intersection & Union : never -export type MaybeLazy = T | (() => Promise) \ No newline at end of file +export type MaybeLazy = T | (() => Promise) + +// Copied and modified from [type-fest](https://github.com/sindresorhus/type-fest/blob/main/source/replace.d.ts) +export type ReplaceAll< + Input extends string, + Search extends string, + Replacement extends string +> = Input extends `${infer Head}${Search}${infer Tail}` + ? `${Head}${Replacement}${ReplaceAll}` + : Input \ No newline at end of file