.ts
TypeScript
(application/typescript)
import { AppRoute, AppRoutePaths, AppRoutesParams } from "../../routes.defs";

export default function buildRouteLink<P extends AppRoute>(
  route: P,
  routeParams: "params" extends keyof AppRoutesParams[P]
    ? AppRoutesParams[P]["params"]
    : {} | null
): typeof AppRoutePaths[P] {
  const path = AppRoutePaths[route];

  if (
    routeParams == null ||
    (routeParams != null &&
      typeof routeParams === "object" &&
      Object.keys(routeParams as any).length <= 0)
  ) {
    return path;
  }

  const paramsEntries =
    typeof routeParams === "object" ? Object.entries(routeParams as never) : [];

  let pathParts = path.split("/");
  let linkBuilder = [] as string[];

  paramsEntries.forEach(([k, v]) => {
    const keyRegExp = new RegExp(`:${k}`, "g");
    pathParts = pathParts.map((part) => {
      if (Array.isArray(part.match(keyRegExp))) {
        return part.replace(keyRegExp, `${String(v)}`);
      } else if (k === "*" && part === "*") {
        return String(v);
      }
      return part;
    });
  });

  pathParts.map((part) => linkBuilder.push(part));
  return linkBuilder.join("/");
}

export function buildPathLink<P extends AppRoute>(
  path: string,
  routeParams: "params" extends keyof AppRoutesParams[P]
    ? AppRoutesParams[P]["params"]
    : undefined
): string {
  const paramsEntries =
    typeof routeParams === "object" ? Object.entries(routeParams as never) : [];

  let pathParts = path.split("/");
  let linkBuilder = [] as string[];

  paramsEntries.forEach(([k, v]) => {
    const keyRegExp = new RegExp(`:${k}`, "g");
    pathParts = pathParts.map((part) => {
      if (Array.isArray(part.match(keyRegExp))) {
        return part.replace(keyRegExp, `${String(v)}`);
      } else if (k === "*" && part === "*") {
        return String(v);
      }
      return part;
    });
  });

  pathParts.map((part) => linkBuilder.push(part));
  return linkBuilder.join("/");
}