routerViewLocationKey,
} from './injectionSymbols'
import { addDevtools } from './devtools'
-import { RouteNamedMap, RouteNamedMapGeneric } from './types/named'
+import { RouteNamedMap } from './types/named'
/**
* Internal type to define an ErrorHandler
*
* @param to - Route location to navigate to
*/
- push<
- RouteMap extends RouteNamedMapGeneric = RouteNamedMap<Options['routes']>,
- Name extends keyof RouteMap = keyof RouteNamedMap<Options['routes']>
- >(
- to: RouteNamedMapGeneric extends RouteMap
- ? RouteLocationRaw
- : RouteLocationNamedRaw<RouteMap, Name> | RouteLocationPathRaw | string
+ push(
+ to:
+ | RouteLocationNamedRaw<RouteNamedMap<Options['routes']>>
+ | string
+ | RouteLocationPathRaw
): Promise<NavigationFailure | void | undefined>
/**
*
* @param to - Route location to navigate to
*/
- replace<
- RouteMap extends RouteNamedMapGeneric = RouteNamedMap<Options['routes']>,
- Name extends keyof RouteMap = keyof RouteNamedMap<Options['routes']>
- >(
- to: RouteNamedMapGeneric extends RouteMap
- ? RouteLocationRaw
- : RouteLocationNamedRaw<RouteMap, Name> | RouteLocationPathRaw | string
+ replace(
+ to:
+ | RouteLocationNamedRaw<RouteNamedMap<Options['routes']>>
+ | string
+ | RouteLocationPathRaw
): Promise<NavigationFailure | void | undefined>
/**
import { RouteRecord, RouteRecordNormalized } from '../matcher/types'
import { HistoryState } from '../history/common'
import { NavigationFailure } from '../errors'
-import { RouteNamedMapGeneric } from './named'
+import { RouteNamedInfo, RouteNamedMapGeneric } from './named'
export type Lazy<T> = () => Promise<T>
export type Override<T, U> = Pick<T, Exclude<keyof T, keyof U>> & U
* @internal
*/
export interface LocationAsRelativeRaw<
- RouteMap extends RouteNamedMapGeneric = RouteNamedMapGeneric,
- Name extends keyof RouteMap = keyof RouteMap
+ Name extends RouteRecordName = RouteRecordName,
+ Info extends RouteNamedInfo = RouteNamedInfo
> {
- name?: RouteNamedMapGeneric extends RouteMap ? RouteRecordName : Name
- params?: RouteNamedMapGeneric extends RouteMap
- ? RouteParamsRaw
- : RouteMap[Name]['paramsRaw']
+ name?: Name
+ params?: Info extends RouteNamedInfo<any, any, infer ParamsRaw>
+ ? ParamsRaw
+ : RouteParamsRaw
}
-// this one didn't work 🤔
-// export type LocationAsRelativeRaw<
-// RouteMap extends RouteNamedMapGeneric = RouteNamedMapGeneric
-// > = {
-// [N in keyof RouteMap]: {
-// name?: N
-// params?: RouteMap[N]['paramsRaw']
-// }
-// }[keyof RouteMap]
-
+/**
+ * @internal
+ */
export interface LocationAsRelative<
- RouteMap extends RouteNamedMapGeneric = RouteNamedMapGeneric,
- Name extends keyof RouteMap = keyof RouteMap
+ Info extends RouteNamedInfo = RouteNamedInfo
> {
- params?: RouteNamedMapGeneric extends RouteMap
- ? RouteParams
- : RouteMap[Name]['params']
+ params?: Info extends RouteNamedInfo<any, infer Params, any>
+ ? Params
+ : RouteParams
}
export interface RouteLocationOptions {
* @internal
*/
export type RouteLocationNamedRaw<
- RouteMap extends RouteNamedMapGeneric = RouteNamedMapGeneric,
- Name extends keyof RouteMap = keyof RouteMap
-> = RouteQueryAndHash &
- LocationAsRelativeRaw<RouteMap, Name> &
- RouteLocationOptions
+ RouteMap extends RouteNamedMapGeneric = RouteNamedMapGeneric
+> = RouteNamedMapGeneric extends RouteMap
+ ? // allows assigning a RouteLocationRaw to RouteLocationNamedRaw
+ RouteQueryAndHash & LocationAsRelativeRaw & RouteLocationOptions
+ : {
+ [K in Extract<keyof RouteMap, RouteRecordName>]: RouteQueryAndHash &
+ LocationAsRelativeRaw<K, RouteMap[K]> &
+ RouteLocationOptions
+ }[Extract<keyof RouteMap, RouteRecordName>]
export type RouteLocationPathRaw =
| RouteQueryAndHash & LocationAsPath & RouteLocationOptions
-import type { RouteParams, RouteParamsRaw, RouteRecordRaw } from '.'
+import type {
+ RouteParams,
+ RouteParamsRaw,
+ RouteRecordRaw,
+ RouteRecordName,
+} from '.'
import type { _JoinPath, ParamsFromPath, ParamsRawFromPath } from './paths'
export type RouteNamedMap<
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 | symbol
- ? {
- [N in Name]: {
- // name: N
- params: ParamsFromPath<_JoinPath<Prefix, Path>>
- // TODO: ParamsRawFromPath
- paramsRaw: ParamsRawFromPath<_JoinPath<Prefix, Path>>
- path: _JoinPath<Prefix, Path>
- }
+ ? (R extends _RouteNamedRecordBaseInfo<
+ infer Name,
+ infer Path,
+ infer Children
+ >
+ ? (Name extends RouteRecordName
+ ? {
+ [N in Name]: {
+ // name: N
+ params: ParamsFromPath<_JoinPath<Prefix, Path>>
+ // TODO: ParamsRawFromPath
+ paramsRaw: ParamsRawFromPath<_JoinPath<Prefix, Path>>
+ path: _JoinPath<Prefix, Path>
}
+ }
+ : {
+ // NO_NAME: 1
+ }) &
+ // Recurse children
+ (Children extends Readonly<RouteRecordRaw[]>
+ ? RouteNamedMap<Children, _JoinPath<Prefix, Path>>
: {
- // NO_NAME: 1
- }) &
- // Recurse children
- (Children extends Readonly<RouteRecordRaw[]>
- ? RouteNamedMap<Children, _JoinPath<Prefix, Path>>
- : {
- // NO_CHILDREN: 1
- })
- : never // Path must be a string
+ // NO_CHILDREN: 1
+ })
: {
// EMPTY: 1
}) &
// END: 1
}
-export type RouteNamedMapGeneric = Record<
- string | symbol | number,
- {
- params: RouteParams
- paramsRaw: RouteParamsRaw
- path: string
- }
->
+export interface _RouteNamedRecordBaseInfo<
+ Name extends RouteRecordName = RouteRecordName, // we don't care about symbols
+ Path extends string = string,
+ Children extends Readonly<RouteRecordRaw[]> = Readonly<RouteRecordRaw[]>
+> {
+ name?: Name
+ path: Path
+ children?: Children
+}
+
+/**
+ * Generic map of named routes from a list of route records.
+ */
+export type RouteNamedMapGeneric = Record<RouteRecordName, RouteNamedInfo>
+
+/**
+ * Relevant information about a named route record to deduce its params.
+ */
+export interface RouteNamedInfo<
+ Path extends string = string,
+ Params extends RouteParams = RouteParams,
+ ParamsRaw extends RouteParamsRaw = RouteParamsRaw
+> {
+ params: Params
+ paramsRaw: ParamsRaw
+ path: Path
+}
*/
export type ParamsFromPath<P extends string = string> = string extends P
? RouteParams // Generic version
+ : _ExtractParamsPath<_RemoveRegexpFromParam<P>, false> extends Record<
+ any,
+ never
+ >
+ ? Record<any, never>
: _ExtractParamsPath<_RemoveRegexpFromParam<P>, false>
export type ParamsRawFromPath<P extends string = string> = string extends P
? RouteParamsRaw // Generic version
+ : _ExtractParamsPath<_RemoveRegexpFromParam<P>, true> extends Record<
+ any,
+ never
+ >
+ ? Record<any, never>
: _ExtractParamsPath<_RemoveRegexpFromParam<P>, true>
/**
r2[method]({ params: { a: 2 } })
r2[method]({ params: {} })
r2[method]({ params: { opt: 'hey' } })
+ // @ts-expect-error: but not non existent
+ r2[method]({ params: { fake_param: 'hey' } })
// routes with no params
r2[method]({ name: 'nested' })
r2[method]({ name: 'nested', params: {} })
// FIXME: is it possible to support this version
- // // @ts-expect-error: does not accept any params
- // r2[method]({ name: 'nested', params: { eo: 'true' } })
+ // @ts-expect-error: does not accept any params
+ r2[method]({ name: 'nested', params: { id: 2 } })
}
-// still allow generics to be passed for convenience
+// NOTE: not possible if we use the named routes as the point is to provide valid routes only
+// @ts-expect-error
r2.push({} as unknown as RouteLocationRaw)
+// @ts-expect-error
r2.replace({} as unknown as RouteLocationRaw)
// createMap(r2.options.routes, true).
expectType<{ id?: string | null | undefined }>(params('/users/:id?'))
expectType<{ id?: readonly string[] | null | undefined }>(params('/users/:id*'))
+expectType<Record<any, never>>(params('/hello/other/thing'))
+// @ts-expect-error
+expectType<{ thing: 'e' }>(params('/hello/other/thing'))
+
// @ts-expect-error
expectType<{ other: string }>(params('/users/:id'))
// @ts-expect-error