Achieve it with a build plugin instead; https://github.com/posva/unplugin-vue-router
Types were too slow due to their recursive nature and relying on tuples
too much. A build-time type generation is not only reliable and fast but
also enable creating other patterns.
VueUseOptions,
RouteLocation,
RouteLocationNormalized,
- RouteLocationPathRaw,
- RouteLocationString,
- RouteLocationNamedRaw,
} from './types'
import { isSameRouteLocationParams, isSameRouteRecord } from './location'
import { routerKey, routeLocationKey } from './injectionSymbols'
import { RouteRecord } from './matcher/types'
import { NavigationFailure } from './errors'
import { isArray, isBrowser, noop } from './utils'
-import type { Router } from './router'
-import type { RouteNamedMap, RouteStaticPathMap } from './types/named'
-import type { RouterTyped } from './typedRouter'
-export interface RouterLinkOptions<
- Routes extends RouteLocationRaw = RouteLocationRaw
-> {
+export interface RouterLinkOptions {
/**
* Route Location the link should navigate to when clicked on.
*/
- to: Routes
+ to: RouteLocationRaw
/**
* Calls `router.replace` instead of `router.push`.
*/
// TODO: refactor using extra options allowed in router.push. Needs RFC
}
-export interface RouterLinkProps<
- Routes extends RouteLocationRaw = RouteLocationRaw
-> extends RouterLinkOptions<Routes> {
+export interface RouterLinkProps extends RouterLinkOptions {
/**
* Whether RouterLink should not wrap its content in an `a` tag. Useful when
* using `v-slot` to create a custom RouterLink
/**
* Component to render a link that triggers a navigation on click.
*/
-export const RouterLink: RouterLinkTyped = RouterLinkImpl as any
+export const RouterLink: _RouterLinkI = RouterLinkImpl as any
/**
* Typed version of the `RouterLink` component. Its generic defaults to the typed router so it can be inferred
* automatically for JSX.
+ *
+ * @internal
*/
-export interface RouterLinkTyped<R extends Router = RouterTyped> {
+export interface _RouterLinkI {
new (): {
$props: AllowedComponentProps &
ComponentCustomProps &
VNodeProps &
- RouterLinkProps<
- | RouteLocationNamedRaw<RouteNamedMap<R['options']['routes']>>
- | RouteLocationString<RouteStaticPathMap<R['options']['routes']>>
- | RouteLocationPathRaw<RouteStaticPathMap<R['options']['routes']>>
- >
+ RouterLinkProps
$slots: {
default: (arg: UnwrapRef<ReturnType<typeof useLink>>) => VNode[]
RouteLocationNormalizedLoaded,
} from './types'
import { RouterView } from './RouterView'
-import type { RouterLinkTyped } from './RouterLink'
-import type { RouterTyped } from './typedRouter'
+import { RouterLink } from './RouterLink'
+import type { Router } from './router'
declare module '@vue/runtime-core' {
export interface ComponentCustomOptions {
/**
* {@link Router} instance used by the application.
*/
- $router: RouterTyped
+ $router: Router
}
export interface GlobalComponents {
RouterView: typeof RouterView
- RouterLink: RouterLinkTyped<RouterTyped>
+ RouterLink: typeof RouterLink
}
}
RouteParamValueRaw,
RouteLocationNamedRaw,
RouteLocationPathRaw,
- RouteLocationString,
RouteLocationMatched,
RouteLocationOptions,
RouteRecordRedirectOption,
NavigationGuardWithThis,
NavigationHookAfter,
} from './types'
-export type {
- ParamsFromPath,
- ParamsRawFromPath,
- _StripRegex,
- _RemoveUntilClosingPar,
- _ExtractParamsOfPath,
- _ParamExtractResult,
- _ExtractModifier,
- _ModifierExtracTResult,
- _JoinPath,
- _ParamDelimiter,
- _ParamModifier,
-} from './types/paths'
-export type {
- RouteNamedMap,
- RouteStaticPathMap,
- RouteNamedInfo,
- _RouteRecordNamedBaseInfo,
-} from './types/named'
-export type { Config, RouterTyped } from './typedRouter'
export { createRouter } from './router'
export type { Router, RouterOptions, RouterScrollBehavior } from './router'
} from './navigationGuards'
export { RouterLink, useLink } from './RouterLink'
export type {
+ _RouterLinkI,
RouterLinkProps,
UseLinkOptions,
- RouterLinkTyped,
} from './RouterLink'
export { RouterView } from './RouterView'
export type { RouterViewProps } from './RouterView'
-import { InjectionKey, ComputedRef, Ref } from 'vue'
+import type { InjectionKey, ComputedRef, Ref } from 'vue'
import { RouteLocationNormalizedLoaded } from './types'
import { RouteRecordNormalized } from './matcher/types'
-import { RouterTyped } from './typedRouter'
+import type { Router } from './router'
/**
* RouteRecord being rendered by the closest ancestor Router View. Used for
*
* @internal
*/
-export const routerKey = Symbol(
- __DEV__ ? 'router' : ''
-) as InjectionKey<RouterTyped>
+export const routerKey = Symbol(__DEV__ ? 'router' : '') as InjectionKey<Router>
/**
* Allows overriding the current route returned by `useRoute` in tests. rl
RouteLocationOptions,
MatcherLocationRaw,
RouteParams,
- RouteLocationNamedRaw,
- RouteLocationPathRaw,
- RouteLocationString,
} from './types'
import { RouterHistory, HistoryState, NavigationType } from './history/common'
import {
routerViewLocationKey,
} from './injectionSymbols'
import { addDevtools } from './devtools'
-import { RouteNamedMap, RouteStaticPathMap } from './types/named'
/**
* Internal type to define an ErrorHandler
}
/**
- * Router instance. **The `Options` generic is internal**.
+ * Router instance.
*/
-export interface Router<Options extends RouterOptions = RouterOptions> {
+export interface Router {
/**
* @internal
*/
/**
* Original options object passed to create the Router
*/
- readonly options: Options
+ readonly options: RouterOptions
/**
* Allows turning off the listening of history events. This is a low level api for micro-frontends.
*
* @param to - Route location to navigate to
*/
- push(
- to:
- | RouteLocationNamedRaw<RouteNamedMap<Options['routes']>>
- | RouteLocationString<RouteStaticPathMap<Options['routes']>>
- | RouteLocationPathRaw<RouteStaticPathMap<Options['routes']>>
- ): Promise<NavigationFailure | void | undefined>
+ push(to: RouteLocationRaw): Promise<NavigationFailure | void | undefined>
/**
* Programmatically navigate to a new URL by replacing the current entry in
*
* @param to - Route location to navigate to
*/
- replace(
- to:
- | RouteLocationNamedRaw<RouteNamedMap<Options['routes']>>
- | RouteLocationString<RouteStaticPathMap<Options['routes']>>
- | RouteLocationPathRaw<RouteStaticPathMap<Options['routes']>>
- ): Promise<NavigationFailure | void | undefined>
+ replace(to: RouteLocationRaw): Promise<NavigationFailure | void | undefined>
/**
* Go back in history if possible by calling `history.back()`. Equivalent to
*
* @param options - {@link RouterOptions}
*/
-export function createRouter<Options extends RouterOptions>(
- options: Options
-): Router<Options> {
+export function createRouter(options: RouterOptions): Router {
const matcher = createRouterMatcher(options.routes, options)
const parseQuery = options.parseQuery || originalParseQuery
const stringifyQuery = options.stringifyQuery || originalStringifyQuery
let started: boolean | undefined
const installedApps = new Set<App>()
- const router: Router<Options> = {
+ const router: Router = {
currentRoute,
listening: true,
+++ /dev/null
-import type { Router } from './router'
-
-/**
- * Vue Router Configuration that allows to add global types for better type support.
- *
- * @example
- *
- * ```ts
- * const router = createRouter({
- * // ...
- * routes: [
- * // ...
- * ] as const // IMPORTANT
- * })
- *
- * declare module 'vue-router' {
- * export interface Config {
- * // allow global functions to get a typed router
- * Router: typeof router
- * }
- * }
- * ```
- */
-export interface Config {
- // Router: unknown
-}
-
-export type RouterTyped = Config extends Record<'Router', infer R> ? R : Router
import { RouteRecord, RouteRecordNormalized } from '../matcher/types'
import { HistoryState } from '../history/common'
import { NavigationFailure } from '../errors'
-import {
- RouteNamedInfo,
- RouteNamedMapGeneric,
- RouteStaticPathMapGeneric,
-} from './named'
-import { LiteralUnion } from './utils'
export type Lazy<T> = () => Promise<T>
export type Override<T, U> = Pick<T, Exclude<keyof T, keyof U>> & U
/**
* @internal
*/
-export interface LocationAsRelativeRaw<
- Name extends RouteRecordName = RouteRecordName,
- Info extends RouteNamedInfo = RouteNamedInfo
-> {
- name?: Name
- params?: Info extends RouteNamedInfo<any, any, infer ParamsRaw>
- ? ParamsRaw
- : RouteParamsRaw
+export interface LocationAsRelativeRaw {
+ name?: string
+ params?: RouteParamsRaw
}
/**
* @internal
*/
-export interface MatcherLocationAsRelative<
- Info extends RouteNamedInfo = RouteNamedInfo
-> {
- params?: Info extends RouteNamedInfo<any, infer Params, any>
- ? Params
- : RouteParams
+export interface MatcherLocationAsRelative {
+ params?: RouteParams
}
/**
| RouteLocationPathRaw
| RouteLocationNamedRaw
-/**
- * Route location that can infer full path locations
- *
- * @internal
- */
-export type RouteLocationString<
- RouteMap extends RouteStaticPathMapGeneric = RouteStaticPathMapGeneric
-> = RouteStaticPathMapGeneric extends RouteMap
- ? string
- : LiteralUnion<
- {
- [K in keyof RouteMap]: RouteMap[K]
- }[keyof RouteMap],
- string
- >
-
/**
* Route Location that can infer the necessary params based on the name.
*
* @internal
*/
-export type RouteLocationNamedRaw<
- RouteMap extends RouteNamedMapGeneric = RouteNamedMapGeneric
-> = RouteNamedMapGeneric extends RouteMap
- ? // allows assigning a RouteLocationRaw to RouteLocationNamedRaw
- RouteQueryAndHash & LocationAsRelativeRaw & RouteLocationOptions
- : {
- [K in Extract<keyof RouteMap, RouteRecordName>]: LocationAsRelativeRaw<
- K,
- RouteMap[K]
- >
- }[Extract<keyof RouteMap, RouteRecordName>] &
- RouteQueryAndHash &
- RouteLocationOptions
+export interface RouteLocationNamedRaw
+ extends RouteQueryAndHash,
+ LocationAsRelativeRaw,
+ RouteLocationOptions {}
/**
* Route Location that can infer the possible paths.
*
* @internal
*/
-export type RouteLocationPathRaw<
- RouteMap extends RouteStaticPathMapGeneric = RouteStaticPathMapGeneric
-> = RouteStaticPathMapGeneric extends RouteMap
- ? // allows assigning a RouteLocationRaw to RouteLocationPath
- RouteQueryAndHash & MatcherLocationAsPath & RouteLocationOptions
- : RouteQueryAndHash &
- RouteLocationOptions &
- MatcherLocationAsPath<
- LiteralUnion<
- { [K in keyof RouteMap]: RouteMap[K] }[keyof RouteMap],
- string
- >
- >
+export interface RouteLocationPathRaw
+ extends RouteQueryAndHash,
+ MatcherLocationAsPath,
+ RouteLocationOptions {}
export interface RouteLocationMatched extends RouteRecordNormalized {
// components cannot be Lazy<RouteComponent>
+++ /dev/null
-import type {
- RouteParams,
- RouteParamsRaw,
- RouteRecordRaw,
- RouteRecordName,
-} from '.'
-import type { _JoinPath, ParamsFromPath, ParamsRawFromPath } from './paths'
-
-/**
- * Creates a map with each named route as a properties. Each property contains the type of the params in raw and
- * normalized versions as well as the raw path.
- * @internal
- */
-export type RouteNamedMap<
- Routes extends Readonly<RouteRecordRaw[]>,
- Prefix extends string = ''
-> = Routes extends readonly [infer R, ...infer Rest]
- ? Rest extends Readonly<RouteRecordRaw[]>
- ? (R extends _RouteRecordNamedBaseInfo<
- infer Name,
- infer Path,
- infer Children
- >
- ? (Name extends RouteRecordName
- ? {
- [N in Name]: {
- // name: N
- params: ParamsFromPath<_JoinPath<Prefix, Path>>
- paramsRaw: ParamsRawFromPath<_JoinPath<Prefix, Path>>
- path: _JoinPath<Prefix, Path>
- }
- }
- : {
- // NO_NAME: 1
- }) &
- // Recurse children
- (Children extends Readonly<RouteRecordRaw[]>
- ? RouteNamedMap<Children, _JoinPath<Prefix, Path>>
- : {
- // NO_CHILDREN: 1
- })
- : {
- // EMPTY: 1
- }) &
- RouteNamedMap<Rest, Prefix>
- : never // R must be a valid route record
- : {
- // END: 1
- }
-
-/**
- * @internal
- */
-export type RouteStaticPathMap<
- Routes extends Readonly<RouteRecordRaw[]>,
- Prefix extends string = ''
-> = Routes extends readonly [infer R, ...infer Rest]
- ? Rest extends Readonly<RouteRecordRaw[]>
- ? (R extends _RouteRecordNamedBaseInfo<
- infer _Name,
- infer Path,
- infer Children
- >
- ? {
- [P in Path as _JoinPath<Prefix, Path>]: _JoinPath<Prefix, Path>
- } & (Children extends Readonly<RouteRecordRaw[]> // Recurse children
- ? RouteStaticPathMap<Children, _JoinPath<Prefix, Path>>
- : {
- // NO_CHILDREN: 1
- })
- : never) & // R must be a valid route record
- // recurse children
- RouteStaticPathMap<Rest, Prefix>
- : {
- // EMPTY: 1
- }
- : {
- // END: 1
- }
-
-/**
- * Important information in a Named Route Record
- * @internal
- */
-export interface _RouteRecordNamedBaseInfo<
- 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.
- *
- * @internal
- */
-export type RouteNamedMapGeneric = Record<RouteRecordName, RouteNamedInfo>
-
-/**
- * Generic map of routes paths from a list of route records.
- *
- * @internal
- */
-export type RouteStaticPathMapGeneric = Record<string, string>
-
-/**
- * Relevant information about a named route record to deduce its params.
- *
- * @internal
- */
-export interface RouteNamedInfo<
- Path extends string = string,
- Params extends RouteParams = RouteParams,
- ParamsRaw extends RouteParamsRaw = RouteParamsRaw
-> {
- params: Params
- paramsRaw: ParamsRaw
- path: Path
-}
+++ /dev/null
-import { RouteParamValueRaw } from '.'
-import { Simplify, _AlphaNumeric } from './utils'
-
-/**
- * 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> =
- P extends `${string}:${string}`
- ? Simplify<_ExtractParamsOfPath<P, false>>
- : Record<any, never>
-
-export type ParamsRawFromPath<P extends string = string> =
- P extends `${string}:${string}`
- ? Simplify<_ExtractParamsOfPath<P, true>>
- : Record<any, never>
-
-/**
- * Possible param modifiers.
- *
- * @internal
- */
-export type _ParamModifier = '+' | '?' | '*'
-
-/**
- * Characters that mark the end of a param. In reality, there is a lot more than
- * this as only alphanumerical + _ are accepted as params but that is impossible
- * to achieve with TS and in practice, This set should cover them all. TODO: Add
- * missing characters that do not need to be encoded.
- *
- * @internal
- */
-export type _ParamDelimiter =
- | '-'
- | '/'
- | '%'
- | ':'
- | '('
- | '\\'
- | ';'
- | ','
- | '&'
- | '!'
- | "'"
- | '='
- | '@'
- | '['
- | ']'
- | '$'
- | _ParamModifier
-
-/**
- * Given a path, extracts the possible params or \{\} when there are no params.
- *
- * @internal
- */
-export type _ExtractParamsOfPath<
- P extends string,
- isRaw extends boolean
-> = P extends `${string}:${infer HasParam}`
- ? _ExtractParamName<HasParam> extends _ParamExtractResult<
- infer ParamName,
- infer Rest
- >
- ? // ParamName is delimited by something eg: /:id/b/:c
- // let's first remove the regex if there is one then extract the modifier
- _ExtractModifier<_StripRegex<Rest>> extends _ModifierExtracTResult<
- infer Modifier,
- infer Rest2
- >
- ? _ParamToObject<ParamName, Modifier, isRaw> &
- _ExtractParamsOfPath<Rest2, isRaw>
- : never // this should never happen as the modifier can be empty
- : // Nothing after the param: /:id, we are done
- _ParamToObject<HasParam, '', isRaw>
- : {
- // EMPTY: 1
- }
-
-/**
- * Helper type to infer a param name extraction result
- * @internal
- */
-export interface _ParamExtractResult<P extends string, Rest extends string> {
- param: P
- rest: Rest
-}
-
-/**
- * Extracts the param name from a path. Requires to strip off the starting `:`
- *
- * @example
- * ```ts
- * _ExtractParamName<'id/:b'> // 'id'
- * ```
- *
- * @internal
- */
-type _ExtractParamName<
- Tail extends string,
- Head extends string = ''
-> = Tail extends `${_AlphaNumeric}${infer Rest}`
- ? Tail extends `${infer C}${Rest}`
- ? // Keep extracting other alphanumeric chars
- _ExtractParamName<Rest, `${Head}${C}`>
- : never // ERR
- : // end the recursion
- _ParamExtractResult<Head, Tail>
-
-/**
- * We consider a what comes after a param, e.g. For `/:id(\\d+)+/edit`, it would be `(\\d+)+/edit`. This should output
- * everything after the regex while handling escaped `)`: `+/edit`. Note this type should be used with a string that
- * starts with `(` as it will remove everything until the closing parenthesis `)`.
- *
- * @internal
- */
-export type _StripRegex<S extends string> =
- // do we have an escaped closing parenthesis?
- S extends `(${infer A}\\)${infer Rest}`
- ? // the actual regexp finished before, A has no escaped )
- A extends `${string})${infer Rest2}`
- ? // Rebuild the rest
- `${Rest2}\\)${Rest}` // job done
- : // NOTE: expensive type when there are multiple custom regex. It's a good idea to avoid multiple custom regexs in paths. Only use custom regexs when necessary or cast the string type: `path: /:id(...)/rest` as '/:id/rest'
- _RemoveUntilClosingPar<Rest> // we keep removing
- : // simple case with no escaping
- S extends `(${string})${infer Rest}`
- ? // extract the modifier if there is one
- Rest
- : // nothing to remove
- S
-
-/**
- * Helper type to infer a modifier extraction result.
- *
- * @internal
- */
-export interface _ModifierExtracTResult<
- M extends _ParamModifier | '',
- Rest extends string
-> {
- modifier: M
- rest: Rest
-}
-
-/**
- * Extracts the modifier and the rest of the path. This is meant to be used with everything after the param name, e.g.,
- * given a path of `/:paths(.+)+/end`, it should be given `+/end` and will split the path into `+` and `/end`.
- *
- * @internal
- */
-export type _ExtractModifier<P extends string> =
- P extends `${_ParamModifier}${infer Rest}`
- ? P extends `${infer M}${Rest}`
- ? M extends _ParamModifier
- ? _ModifierExtracTResult<M, Rest>
- : // impossible case
- never
- : // impossible case
- never
- : // No modifier present
- _ModifierExtracTResult<'', P>
-
-/**
- * Gets the possible type of a param based on its modifier M.
- *
- * @internal
- */
-export type _ModifierParamValue<
- M extends _ParamModifier | '' = _ParamModifier | '',
- isRaw extends boolean = false
-> = '' extends M
- ? _ParamValue<isRaw>
- : '+' extends M
- ? _ParamValueOneOrMore<isRaw>
- : '*' extends M
- ? _ParamValueZeroOrMore<isRaw>
- : '?' extends M
- ? _ParamValueZeroOrOne<isRaw>
- : never
-
-/**
- * Utility type for raw and non raw params like :id+
- *
- * @internal
- */
-export type _ParamValueOneOrMore<isRaw extends boolean> = true extends isRaw
- ? readonly [string | number, ...(string | number)[]]
- : readonly [string, ...string[]]
-
-/**
- * Utility type for raw and non raw params like :id*
- *
- * @internal
- */
-export type _ParamValueZeroOrMore<isRaw extends boolean> = true extends isRaw
- ? readonly (string | number)[] | undefined | null
- : readonly string[] | undefined | null
-
-/**
- * Utility type for raw and non raw params like :id?
- *
- * @internal
- */
-export type _ParamValueZeroOrOne<isRaw extends boolean> = true extends isRaw
- ? RouteParamValueRaw
- : string
-
-/**
- * Utility type for raw and non raw params like :id
- *
- * @internal
- */
-export type _ParamValue<isRaw extends boolean> = true extends isRaw
- ? string | number
- : string
-
-/**
- * Given a param name N and its modifier M, creates a param object for the pair.
- *
- * @internal
- */
-export type _ParamToObject<
- N extends string,
- M extends _ParamModifier | '',
- isRaw extends boolean
-> = M extends '?' | '*'
- ? {
- [K in N]?: _ModifierParamValue<M, isRaw>
- }
- : {
- [K in N]: _ModifierParamValue<M, isRaw>
- }
-
-/**
- * Takes the custom regex (and everything after) of a param and strips it off. Must be called with a string that starts
- * with a `(` **after the parenthesis**.
- *
- * @example
- * - `\\d+(?:inner-group\\)-end)/:rest-of-url` becomes `/:rest-of-url`
- *
- * @internal
- */
-export type _RemoveUntilClosingPar<S extends string> =
- // do we have an escaped closing parenthesis?
- S extends `${infer A}\\)${infer Rest}`
- ? // the actual regexp finished before, A has no escaped )
- A extends `${string})${infer Rest2}`
- ? `${Rest2}\\)${Rest}` // job done
- : _RemoveUntilClosingPar<Rest> // we keep removing
- : S extends `${string})${infer Rest}`
- ? Rest
- : never // nothing to remove, should not have been called, easier to spot bugs
-
-/**
- * Joins a prefix and a path putting a `/` between them when necessary
- *
- * @internal
- */
-export type _JoinPath<
- Prefix extends string,
- Path extends string
-> = Path extends `/${string}`
- ? Path
- : '' extends Prefix
- ? never
- : `${Prefix}${Prefix extends `${string}/` ? '' : '/'}${Path}`
import { inject } from 'vue'
import { routerKey, routeLocationKey } from './injectionSymbols'
-import { RouterTyped } from './typedRouter'
+import { Router } from './router'
import { RouteLocationNormalizedLoaded } from './types'
/**
* Returns the router instance. Equivalent to using `$router` inside
* templates.
*/
-export function useRouter(): RouterTyped {
+export function useRouter(): Router {
return inject(routerKey)!
}
expectType<JSX.Element>(<RouterLink class="link" to="/foo" />)
expectType<JSX.Element>(<RouterLink to={{ path: '/foo' }} />)
expectType<JSX.Element>(<RouterLink to={{ path: '/foo' }} custom />)
-// @ts-expect-error: non existing name
-expectError(<RouterLink to={{ name: '' }} />)
// RouterView
expectType<JSX.Element>(<RouterView class="view" />)
+++ /dev/null
-import {
- createRouter,
- createWebHistory,
- RouteRecordRaw,
- expectType,
- RouteNamedMap,
- RouteLocationRaw,
- _JoinPath,
- useRouter,
-} from './index'
-import { DefineComponent } from 'vue'
-
-declare const component: DefineComponent
-declare const components: { default: DefineComponent }
-
-const routeName = Symbol()
-
-const r2 = createRouter({
- history: createWebHistory(),
- routes: [
- { path: '/', component },
- { path: '/foo', component },
- { path: '/users/:id', name: 'UserDetails', component },
- { path: '/no-name', /* no name */ components },
- {
- path: '/nested',
- name: 'nested',
- children: [
- {
- path: ':a',
- name: 'nested-a',
- children: [
- {
- path: 'b',
- children: [{ path: ':c', name: 'nested-c', component }],
- },
- ],
- },
- { path: ':opt?', name: 'optional', component },
- // still skipped
- { path: 'other', name: routeName, component },
- ],
- },
- ] as const,
-})
-
-const methods = ['push', 'replace'] as const
-for (const method of methods) {
- r2.push({ name: 'UserDetails' })
- r2.replace({ name: 'UserDetails' })
-
- // accepts missing params because of relative locations is valid
- r2[method]({ name: 'UserDetails' })
- // @ts-expect-error: but expects a correct id
- r2[method]({ name: 'UserDetails', params: {} })
- // @ts-expect-error: no invalid params
- r2[method]({ name: 'UserDetails', params: { id: '2', nope: 'oops' } })
- // other options are valid
- r2[method]({ name: 'UserDetails', query: { valid: 'true' }, replace: true })
- r2[method]({ name: 'UserDetails', params: { id: '2' } })
- // accepts numbers
- r2[method]({ name: 'UserDetails', params: { id: 2 } })
- // @ts-expect-error: fails on null
- r2[method]({ name: 'UserDetails', params: { id: null } })
- // @ts-expect-error: and undefined
- r2[method]({ name: 'UserDetails', params: { id: undefined } })
- // nested params work too
- r2[method]({ name: 'nested-c', params: { a: '2', c: '3' } })
- r2[method]({ name: 'optional' })
- // optional params are more flexible
- r2[method]({ name: 'optional', params: {} })
- r2[method]({ name: 'optional', params: { opt: 'hey' } })
- r2[method]({ name: 'optional', params: { opt: null } })
- r2[method]({ name: 'optional', params: { opt: undefined } })
- // works with symbols too
- r2[method]({ name: routeName })
- // @ts-expect-error: but not other symbols
- r2[method]({ name: Symbol() })
- // relative push can have any of the params
- 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: { id: 2 } })
-
- // paths
- r2[method]({ path: '/nested' })
- r2[method]({ path: '/nested/:a/b' })
- // with an actual param
- r2[method]({ path: '/nested/a/b' })
- // NOTE: we actually accept any string because of perf bottlenecks due to tuples
- r2[method]({ path: '' })
- r2[method]({ path: '/nope' })
- r2[method]({ path: '/no-name?query' })
- r2[method]({ path: '/no-name#hash' })
-
- r2[method]('/nested')
- r2[method]('/nested/a/b')
-
- // NOTE: same as above
- r2[method]('')
- r2[method]('/nope')
- r2[method]('/no-name?query')
- r2[method]('/no-name#hash')
-}
-
-// 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).
-
-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: { params: { id: string }; path: '/users/:id' }
- nested: { params: {}; path: '/nested' }
- 'nested-a': { params: { a: string }; path: '/nested/:a' }
- 'nested-c': { params: { a: string; c: string }; path: '/nested/:a/b/:c' }
-}>(createMap(r2.options.routes))
-
-expectType<{
- UserDetails: { params: { nope: string } }
- // @ts-expect-error
-}>(createMap(r2.options.routes))
-expectType<{
- UserDetails: { path: '/users' }
- // @ts-expect-error
-}>(createMap(r2.options.routes))
-expectType<{
- 'nested-c': { path: '/' }
- // @ts-expect-error
-}>(createMap(r2.options.routes))
-expectType<{
- 'nested-c': { params: { a: string; d: string } }
- // @ts-expect-error
-}>(createMap(r2.options.routes))
-expectType<{
- nope: { params: {} }
- // @ts-expect-error
-}>(createMap(r2.options.routes))
-
-// declare module '../src' {
-declare module '../dist/vue-router' {
- export interface Config {
- Router: typeof r2
- }
-}
-
-const typedRouter = useRouter()
-// this one is true if we comment out the line with Router: typeof r2
-// expectType<Router>(typedRouter)
-expectType<typeof r2>(typedRouter)
-typedRouter.push({ name: 'UserDetails' })
-// @ts-expect-error
-typedRouter.push({ name: 'nope' })
+++ /dev/null
-import type {
- ParamsFromPath,
- _StripRegex,
- _ExtractParamsOfPath,
- _RemoveUntilClosingPar,
- _ExtractModifier,
- _ModifierExtracTResult,
-} from './'
-import { expectType } from './'
-
-function params<T extends string>(_path: T): ParamsFromPath<T> {
- return {} as any
-}
-
-// simple
-expectType<Record<any, never>>(params('/static'))
-expectType<{ id: string }>(params('/users/:id'))
-// simulate a part of the string unknown at compilation time
-expectType<{ id: string }>(params(`/${encodeURI('')}/:id`))
-expectType<{ id: readonly [string, ...string[]] }>(params('/users/:id+'))
-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
-expectType<{ other: string }>(params('/users/static'))
-
-// at beginning
-expectType<{ id: string }>(params('/:id'))
-expectType<{ id: readonly [string, ...string[]] }>(params('/:id+'))
-expectType<{ id?: string | null | undefined }>(params('/:id?'))
-expectType<{ id?: readonly string[] | null | undefined }>(params('/:id*'))
-
-// with trailing path
-expectType<{ id: string }>(params('/users/:id-more'))
-expectType<{ id: readonly [string, ...string[]] }>(params('/users/:id+-more'))
-expectType<{ id?: string | null | undefined }>(params('/users/:id?-more'))
-expectType<{ id?: readonly string[] | null | undefined }>(
- params('/users/:id*-more')
-)
-
-// multiple
-expectType<{ id: string; b: string }>(params('/users/:id/:b'))
-expectType<{
- id: readonly [string, ...string[]]
- b: readonly [string, ...string[]]
-}>(params('/users/:id+/:b+'))
-expectType<{ id?: string | null | undefined; b?: string | null | undefined }>(
- params('/users/:id?-:b?')
-)
-expectType<{
- id?: readonly string[] | null | undefined
- b?: readonly string[] | null | undefined
-}>(params('/users/:id*/:b*'))
-
-// custom regex
-expectType<{ id: string }>(params('/users/:id(one)'))
-expectType<{ id: string }>(params('/users/:id(\\d+)'))
-expectType<{ id: readonly string[] }>(params('/users/:id(one)+'))
-expectType<{ date: string }>(params('/users/:date(\\d{4}-\\d{2}-\\d{2})'))
-expectType<{ a: string }>(params('/:a(pre-(?:\\d{0,5}\\)-end)'))
-
-expectType<{
- id: readonly [string, ...string[]]
- b: string
- c: string
- d: string
-}>(params('/:id(.*)+/other/:b/:c/:d'))
-
-// special characters
-expectType<{ id: string }>(params('/:id$thing'))
-expectType<{ id: string }>(params('/:id&thing'))
-expectType<{ id: string }>(params('/:id!thing'))
-expectType<{ id: string }>(params('/:id\\*thing'))
-expectType<{ id: string }>(params('/:id\\thing'))
-expectType<{ id: string }>(params("/:id'thing"))
-expectType<{ id: string }>(params('/:id,thing'))
-expectType<{ id: string }>(params('/:id;thing'))
-expectType<{ id: string }>(params('/:id=thing'))
-expectType<{ id: string }>(params('/:id@thing'))
-expectType<{ id: string }>(params('/:id[thing'))
-expectType<{ id: string }>(params('/:id]thing'))
-
-function removeUntilClosingPar<S extends string>(
- _s: S
-): _RemoveUntilClosingPar<S> {
- return '' as any
-}
-
-expectType<''>(removeUntilClosingPar(')'))
-expectType<'+'>(removeUntilClosingPar(')+'))
-expectType<'more'>(removeUntilClosingPar(')more'))
-expectType<''>(removeUntilClosingPar('\\w+)'))
-expectType<'/more-url'>(removeUntilClosingPar('\\w+)/more-url'))
-expectType<'/:p'>(removeUntilClosingPar('\\w+)/:p'))
-expectType<'+'>(removeUntilClosingPar('oe)+'))
-expectType<'/:p(o)'>(removeUntilClosingPar('\\w+)/:p(o)'))
-expectType<'/:p(o)'>(removeUntilClosingPar('(?:no\\)?-end)/:p(o)'))
-expectType<'/:p(o(?:no\\)?-end)'>(
- removeUntilClosingPar('-end)/:p(o(?:no\\)?-end)')
-)
-expectType<':new(eg)other'>(removeUntilClosingPar('customr):new(eg)other'))
-expectType<':new(eg)+other'>(removeUntilClosingPar('customr):new(eg)+other'))
-expectType<'/:new(eg)+other'>(removeUntilClosingPar('customr)/:new(eg)+other'))
-expectType<'?/:new(eg)+other'>(
- removeUntilClosingPar('customr)?/:new(eg)+other')
-)
-
-function stripRegex<S extends string>(_s: S): _StripRegex<S> {
- return '' as any
-}
-
-expectType<'+/edit/'>(stripRegex('(\\d+)+/edit/'))
-expectType<'*'>(stripRegex('(.*)*'))
-expectType<'?/rest'>(stripRegex('?/rest'))
-expectType<'*'>(stripRegex('*'))
-expectType<'-other-stuff'>(stripRegex('-other-stuff'))
-expectType<'/edit'>(stripRegex('/edit'))
-expectType<'?/rest/:other(.*)*'>(stripRegex('?/rest/:other(.*)*'))
-expectType<'+/edit/:other(.*)*'>(stripRegex('(\\d+)+/edit/:other(.*)*'))
-expectType<'?/rest/:other(.*)/more/:b(.*)'>(
- stripRegex('?/rest/:other(.*)/more/:b(.*)')
-)
-
-function extractModifier<S extends string>(_s: S): _ExtractModifier<S> {
- return {} as any
-}
-
-expectType<_ModifierExtracTResult<'', ''>>(extractModifier(''))
-expectType<_ModifierExtracTResult<'', '-rest'>>(extractModifier('-rest'))
-expectType<_ModifierExtracTResult<'', 'edit'>>(extractModifier('edit'))
-expectType<_ModifierExtracTResult<'+', ''>>(extractModifier('+'))
-expectType<_ModifierExtracTResult<'+', '/edit'>>(extractModifier('+/edit'))
-expectType<_ModifierExtracTResult<'+', '/edit/:a?'>>(
- extractModifier('+/edit/:a?')
-)