_RemoveRegexpFromParam,
_RemoveUntilClosingPar,
} from './types/paths'
+export type { RouteNamedMap } from './types/named'
export { createRouter } from './router'
export type { Router, RouterOptions, RouterScrollBehavior } from './router'
*/
redirect?: RouteRecordRedirectOption
- /**
- * Array of nested routes.
- */
- children?: RouteRecordRaw[]
/**
* Aliases for the record. Allows defining extra paths that will behave like a
* copy of the record. Allows having paths shorthands like `/users/:id` and
/**
* Array of nested routes.
*/
- children: RouteRecordRaw[]
+ children: Readonly<RouteRecordRaw[]>
/**
* Allow passing down params as props to the component rendered by `router-view`.
-import { Router } from '../router'
+import type { RouteRecordRaw } from '.'
+import type { Router } from '../router'
+import { JoinPath, ParamsFromPath } from './paths'
/**
* This will flat the routes into an object with `key` === `router.name`
* ```
*/
export interface NamedLocationMap {}
+
+export type RouteNamedMap<
+ Routes extends Readonly<RouteRecordRaw[]>,
+ Prefix extends string = ''
+> = Routes extends readonly [infer R, ...infer Rest]
+ ? Rest extends Readonly<RouteRecordRaw[]>
+ ? (R extends {
+ name?: infer Name
+ path: infer Path
+ children?: infer Children
+ }
+ ? Path extends string
+ ? (Name extends string
+ ? {
+ [N in Name]: ParamsFromPath<JoinPath<Prefix, Path>>
+ }
+ : {
+ // NO_NAME: 1
+ }) &
+ (Children extends Readonly<RouteRecordRaw[]>
+ ? RouteNamedMap<Children, JoinPath<Prefix, Path>>
+ : {
+ // NO_CHILDREN: 1
+ })
+ : never // Path must be a string
+ : {
+ // EMPTY: 1
+ }) &
+ RouteNamedMap<Rest>
+ : never // R must be a valid route record
+ : {
+ // END: 1
+ }
+/**
+ * Extract an object of params given a path like `/users/:id`.
+ *
+ * @example
+ * ```ts
+ * type P = ParamsFromPath<'/:id/b/:c*'> // { id: string; c?: string[] }
+ * ```
+ */
+export type ParamsFromPath<P extends string = string> = string extends P
+ ? PathParams // Generic version
+ : _ExtractParamsPath<_RemoveRegexpFromParam<P>>
+
/**
* Generic possible params from a path (after parsing).
*/
_ExtractParamsPath<Rest>
: {}
-/**
- * Extract an object of params given a path like `/users/:id`.
- */
-export type ParamsFromPath<P extends string = string> = string extends P
- ? PathParams // Generic version
- : _ExtractParamsPath<_RemoveRegexpFromParam<P>>
-
/**
* Gets the possible type of a param based on its modifier M.
*
export type ParamKeysFromPath<P extends string = string> = string extends P
? readonly PathParserParamKey[] // Generic version
: _ExtractPathParamKeys<_RemoveRegexpFromParam<P>>
+
+export type JoinPath<
+ Prefix extends string,
+ Path extends string
+> = Path extends `/${string}`
+ ? Path
+ : '' extends Prefix
+ ? never
+ : `${Prefix}${Prefix extends `${string}/` ? '' : '/'}${Path}`
Router,
ExtractRoutes,
createRouter,
+ createWebHistory,
+ RouteRecordRaw,
+ expectType,
+ RouteNamedMap,
} from './index'
import { DefineComponent } from 'vue'
+import { JoinPath } from 'src/types/paths'
declare const Comp: DefineComponent
+declare const component: DefineComponent
+declare const components: { default: DefineComponent }
const routes = [
{
},
] as const
+export function defineRoutes<
+ Path extends string,
+ Routes extends Readonly<RouteRecordRaw<Path>[]>
+>(routes: Routes): Routes {
+ return routes
+}
+
+const r2 = createRouter({
+ history: createWebHistory(),
+ routes: [
+ { path: '/users/:id', name: 'UserDetails', component },
+ { path: '/no-name', /* no name */ component },
+ {
+ path: '/nested',
+ name: 'nested',
+ children: [
+ {
+ path: ':a',
+ name: 'nested-a',
+ children: [
+ {
+ path: 'b',
+ children: [{ path: ':c', name: 'nested-c', component }],
+ },
+ ],
+ },
+ ],
+ },
+ ] as const,
+})
+
+function joinPath<A extends string, B extends string>(
+ prefix: A,
+ path: B
+): JoinPath<A, B> {
+ return '' as any
+}
+
+function createMap<R extends Readonly<RouteRecordRaw[]>>(
+ routes: R
+): RouteNamedMap<R> {
+ return {} as any
+}
+
+expectType<'/nested/:a'>(joinPath('/nested', ':a'))
+expectType<'/nested/:a'>(joinPath('/nested/', ':a'))
+expectType<'/:a'>(joinPath('/nested', '/:a'))
+
+expectType<{
+ UserDetails: { id: string }
+ nested: {}
+ 'nested-a': { a: string }
+ 'nested-c': { a: string; c: string }
+}>(createMap(r2.options.routes))
+
+expectType<{
+ UserDetails: { nope: string }
+ // @ts-expect-error
+}>(createMap(r2.options.routes))
+expectType<{
+ 'nested-c': { a: string; d: string }
+ // @ts-expect-error
+}>(createMap(r2.options.routes))
+expectType<{
+ nope: {}
+ // @ts-expect-error
+}>(createMap(r2.options.routes))
+
declare const typed: ExtractNamedRoutes<typeof routes>
typed['my-other-path']