]> git.ipfire.org Git - thirdparty/vuejs/router.git/commitdiff
refactor: put TOut type param first
authorEduardo San Martin Morote <posva13@gmail.com>
Mon, 11 Aug 2025 08:05:48 +0000 (10:05 +0200)
committerEduardo San Martin Morote <posva13@gmail.com>
Mon, 11 Aug 2025 08:05:48 +0000 (10:05 +0200)
packages/experiments-playground/src/router/index.ts
packages/router/src/experimental/index.ts
packages/router/src/experimental/route-resolver/matchers/matcher-pattern.ts

index 27789265e3003e6ab64aadf856114133fb0e1118..c8b5b2b142f9ba1c4eec29794e74a6f89c1c4f30 100644 (file)
@@ -3,10 +3,9 @@ import {
   experimental_createRouter,
   createStaticResolver,
   MatcherPatternPathStatic,
-  MatcherPatternPathStar,
   MatcherPatternPathCustomParams,
   normalizeRouteRecord,
-  PARAM_INTEGER,
+  PARAM_PARSER_INTEGER,
 } from 'vue-router/experimental'
 import type {
   EXPERIMENTAL_RouteRecordNormalized_Matchable,
@@ -144,7 +143,10 @@ const r_profiles_detail = normalizeRouteRecord({
   path: new MatcherPatternPathCustomParams(
     /^\/profiles\/([^/]+)$/i,
     {
-      userId: PARAM_INTEGER,
+      // this version handles all kind of params but in practice,
+      // the generation should recognize this is a single required param
+      // and therefore userId is of type number
+      userId: PARAM_PARSER_INTEGER,
     },
     ['profiles', 0]
   ),
index ab6f1c6ce0488b9cb34256005e73c36963f6583d..595128ee2ac3c65bf17eacc4bd5ce69645ef7268 100644 (file)
@@ -25,7 +25,8 @@ export {
   MatcherPatternPathCustomParams,
   // custom param parsers
   // TODO: find a more elegant format than having 4 variants per param type
-  PARAM_INTEGER,
+  PARAM_PARSER_INTEGER,
+  PARAM_INTEGER_SINGLE,
   PARAM_NUMBER_OPTIONAL,
   PARAM_NUMBER_REPEATABLE,
   PARAM_NUMBER_REPEATABLE_OPTIONAL,
index 72d6ca0a49a5a652aa315f79a636e802ebb1b29d..89fc978c354551f465083d7664f719f44fd2a18e 100644 (file)
@@ -121,20 +121,16 @@ export class MatcherPatternPathStar
 // new MatcherPatternPathStatic('/team')
 
 export interface Param_GetSet<
-  TIn extends string | string[] | null | undefined =
-    | string
-    | string[]
-    | null
-    | undefined,
   TOut = string | string[] | null,
+  TIn extends string | string[] | null = string | string[] | null,
 > {
   get?: (value: NoInfer<TIn>) => TOut
   set?: (value: NoInfer<TOut>) => TIn
 }
 
 export type ParamParser_Generic =
-  | Param_GetSet<string, any>
-  | Param_GetSet<string[], any>
+  | Param_GetSet<any, string>
+  | Param_GetSet<any, string[]>
 // TODO: these are possible values for optional params
 // | null | undefined
 
@@ -147,7 +143,7 @@ export type ParamParser_Generic =
 export function defineParamParser<TOut, TIn extends string | string[]>(parser: {
   get?: (value: TIn) => TOut
   set?: (value: TOut) => TIn
-}): Param_GetSet<TIn, TOut> {
+}): Param_GetSet<TOut, TIn> {
   return parser
 }
 
@@ -189,7 +185,7 @@ export const PATH_PARAM_DEFAULT_PARSER: Param_GetSet = {
  */
 
 export type ParamsFromParsers<P extends Record<string, ParamParser_Generic>> = {
-  [K in keyof P]: P[K] extends Param_GetSet<infer TIn, infer TOut>
+  [K in keyof P]: P[K] extends Param_GetSet<infer TOut, infer TIn>
     ? unknown extends TOut // if any or unknown, use the value of TIn, which defaults to string | string[]
       ? TIn
       : TOut
@@ -199,7 +195,7 @@ export type ParamsFromParsers<P extends Record<string, ParamParser_Generic>> = {
 interface MatcherPatternPathCustomParamOptions<
   TIn extends string | string[] | null = string | string[] | null,
   TOut = string | string[] | null,
-> extends Param_GetSet<TIn, TOut> {
+> extends Param_GetSet<TOut, TIn> {
   repeat?: boolean
   // NOTE: not needed because in the regexp, the value is undefined if
   // the group is optional and not given
@@ -221,7 +217,7 @@ type ExtractParamTypeFromOptions<TParamsOptions> = {
 
 const IS_INTEGER_RE = /^-?[1-9]\d*$/
 
-export const PARAM_INTEGER = {
+export const PARAM_INTEGER_SINGLE = {
   get: (value: string) => {
     if (IS_INTEGER_RE.test(value)) {
       const num = Number(value)
@@ -232,26 +228,46 @@ export const PARAM_INTEGER = {
     throw miss()
   },
   set: (value: number) => String(value),
-} satisfies Param_GetSet<string, number>
+} satisfies Param_GetSet<number, string>
 
 export const PARAM_NUMBER_OPTIONAL = {
   get: (value: string | null) =>
-    value == null ? null : PARAM_INTEGER.get(value),
+    value == null ? null : PARAM_INTEGER_SINGLE.get(value),
   set: (value: number | null) =>
-    value != null ? PARAM_INTEGER.set(value) : null,
-} satisfies Param_GetSet<string | null, number | null>
+    value != null ? PARAM_INTEGER_SINGLE.set(value) : null,
+} satisfies Param_GetSet<number | null, string | null>
 
 export const PARAM_NUMBER_REPEATABLE = {
-  get: (value: string[]) => value.map(PARAM_INTEGER.get),
-  set: (value: number[]) => value.map(PARAM_INTEGER.set),
-} satisfies Param_GetSet<string[], number[]>
+  get: (value: string[]) => value.map(PARAM_INTEGER_SINGLE.get),
+  set: (value: number[]) => value.map(PARAM_INTEGER_SINGLE.set),
+} satisfies Param_GetSet<number[], string[]>
 
 export const PARAM_NUMBER_REPEATABLE_OPTIONAL = {
   get: (value: string[] | null) =>
     value == null ? null : PARAM_NUMBER_REPEATABLE.get(value),
   set: (value: number[] | null) =>
     value != null ? PARAM_NUMBER_REPEATABLE.set(value) : null,
-} satisfies Param_GetSet<string[] | null, number[] | null>
+} satisfies Param_GetSet<number[] | null, string[] | null>
+
+/**
+ * Native Param parser for integers.
+ *
+ * @internal
+ */
+export const PARAM_PARSER_INTEGER: Param_GetSet<number | number[] | null> = {
+  get: value =>
+    Array.isArray(value)
+      ? PARAM_NUMBER_REPEATABLE.get(value)
+      : value != null
+        ? PARAM_INTEGER_SINGLE.get(value)
+        : null,
+  set: value =>
+    Array.isArray(value)
+      ? PARAM_NUMBER_REPEATABLE.set(value)
+      : value != null
+        ? PARAM_INTEGER_SINGLE.set(value)
+        : null,
+}
 
 export class MatcherPatternPathCustomParams<
   TParamsOptions,