/** * Constructs a URL by appending query parameters to a given path. * * @template TVariables - The shape of the params. * * @param path - Path. * @param params - Optional. Params to be added as query parameters to the URL. * * @returns The constructed URL. */ function buildUrl< TVariables extends Record = Record >(path: string, params?: TVariables): string { if (params === undefined || Object.keys(params).length === 0) { return path; } const match: RegExpMatchArray | null = path.match( /^(?[^?]*)(?:\?(?.*))?$/ ); if (match === null) { throw new Error("Error parsing the given path"); } const queryString = new URLSearchParams(match.groups?.queryString); Object.entries(params).forEach(([key, value]) => { if (Array.isArray(value)) { if (queryString.has(key)) { queryString.delete(key); } value.forEach((item: unknown): void => { queryString.append(`${key}[]`, String(item)); }); } else { queryString.set(key, String(value)); } }); return `${match.groups?.path}?${queryString.toString()}`; }