Can we streamline a generic overloaded function's signature to make it more concise?

I have developed a streamlined Axios wrapper function that integrates zod-parsing and presents a discriminated union for improved error handling. While the implementation successfully maintains the default behavior of Axios to throw errors in certain cases by passing { throw: true } to the config parameter through overloading, I find the current setup verbose. Is there a way to refactor the overloading to reduce redundancy and enhance the DRY principle? My goal is to declare the generics Schema and Parsed just once instead of repeating them three times.

import type { AxiosRequestConfig } from 'axios';
import * as z from 'zod';
import * as URLS from '~/constants/api-url-constants';
import { coerceError } from '~/utils';

type Result<T> = { ok: true; response: T } | { ok: false; error: Error };
type Url = string | ((urls: typeof URLS) => string);

interface Config<Schema extends z.Schema, Throw extends boolean>
  extends AxiosRequestConfig {
  schema?: Schema | ((zod: typeof z) => Schema);
  throw?: Catch;
}

/**
 * This Axios wrapper function accepts Zod-schema to parse response data,
 * providing typed response inferred from the schema's output type.
 * Schema validations occur within `config.transformResponse`,
 * allowing detection of failed Zod parsing.
 *
 * By default, it returns a discriminated union for error handling.
 * Enable overload `config.catch` to mimic native Axios behavior and throw unsuccessful API calls.
 */
async function axiosWrapper<
  Schema extends z.Schema = z.ZodUnknown,
  Parsed = z.output<Schema>,
>(url: Url, config: Config<Schema, false>): Promise<Result<Parsed>>;

async function axiosWrapper<
  Schema extends z.Schema = z.ZodUnknown,
  Parsed = z.output<Schema>,
>(url: Url, config: Config<Schema, true>): Promise<Parsed>;

async function axiosWrapper<
  Schema extends z.Schema = z.ZodUnknown,
  Parsed = z.output<Schema>,
>(url: Url, config: Config<Schema, boolean>): Promise<Result<Parsed> | Parsed> {
  // …implementation
}

Answer â„–1

There is a way to reduce the amount of generic code you need to write and eliminate redundancy in this context. However, making these changes will alter how the function is utilized.

For instance, the following approach could be effective:

type CustomAxiosFunction<
  Schema extends z.Schema = z.ZodUnknown,
  Parsed = z.output<Schema>
> = {
  (url: Url, config: Config<Schema, false>): Promise<Result<Parsed>>;
  (url: Url, config: Config<Schema, true>): Promise<Parsed>;
};

export const generateCustomAxiosFunction = <
  Schema extends z.Schema = z.ZodUnknown,
  Parsed = z.output<Schema>
>(): CustomAxiosFunction<Schema, Parsed> => {
  return (url: Url, config: Config<Schema, boolean>) => {
    /** functionality */
  };
}

In this case, a wrapper function must be created so that it's feasible to pass generics to the underlying implementation function as well.

The downside is that the function now needs to be used like this:

const customAxiosFunc = generateCustomAxiosFunction</** your generics */>();

customAxiosFunc(/** your arguments */)

Instead of the previous method where you could simply do:

customAxiosFunc</** your generics */>(/** your arguments */)

I recommend continuing to refine the generics and sticking with your current approach to function overloading.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

ESLint is reminding you that the `parserOptions.project` setting must be configured to reference the tsconfig.json files specific to your

Within my NX Workspace, I am developing a NestJS-Angular project. Upon running nx lint, an error is triggered with the following message: Error: A lint rule requiring the TypeScript type-checker to be fully available has been attempted, but `parserOptions. ...

Oops! Angular2 couldn't find a provider for HttpHandler

I have been working on implementing HttpCache through an interceptor. Below is the code snippet for caching-interceptor.service.ts: import { HttpRequest, HttpResponse, HttpInterceptor, HttpHandler, HttpEvent } from '@angular/common/http' import ...

Securing Your Next.js Web App with Session Authentication

I have encountered a challenge while integrating NextAuth authentication into my React.js web application. To ensure seamless user authentication across the entire app, I am attempting to wrap a SessionProvider around the root component. However, VSCode ...

Instructions on resolving the issue: The type 'string | ChatCompletionContentPart[] | null' cannot be assigned to type 'ReactNode'

I've been working on my first Saas App, similar to a ChatGPT, using NextJs with the OpenAI Api. Most of the development was based on a YouTube tutorial until I encountered two errors caused by an update in the OpenAI version. Despite trying various so ...

Modify the color of the select element when it is in an open state

If you're new to Material UI, I have a select element that I would like to change the color of. When 'None' is selected, I want the background color of the input field above it to match the 'None' section. Then, when the dropdown m ...

"Improve your Angular ngrx workflow by utilizing the sandbox pattern to steer clear of

Currently, I'm trying to determine whether my implementation of the ngrx and sandbox pattern is effective. Here's the issue I'm facing: getFiles(userId: number, companyId: number) { this.fileService.getFiles(userId, companyId).subscribe(re ...

Tips for verifying internet connectivity and accessing stored data in localstorage

I'm working on my home.ts file and I need to use localStorage items when the internet connection is offline. However, I am encountering numerous errors when trying to add an IF condition in my code. Specifically, I want to access the getItem method be ...

Save Component Characteristics in a type-safe array

Is it possible in Svelte to define a strongly typed array that matches the properties exported by a specific component? For instance, if I have the following code snippet, const things = [], is there a way for Svelte to recognize that each item within the ...

Enhance your Vuex action types in Typescript by adding new actions or extending existing

I'm new to Typescript and I'm exploring ways to add specific type structure to all Actions declared in Vue store without repeating them in every Vuex module file. For instance, instead of manually defining types for each action in every store fi ...

When I try to integrate Three.js into my React application, it mysteriously causes my root HTML element

While attempting to utilize Three.js in Typescript react, I successfully rendered a Dodecahedron figure along with random stars. However, my intention was to incorporate some markup into my Three.js scene using React. Unfortunately, when I render the Three ...

Is there a way to sort through nested objects with unspecified keys?

I'm looking to extract specific information from a nested object with unknown keys and create a new array with it. This data is retrieved from the CUPS API, where printer names act as keys. I want to filter based on conditions like 'printer-stat ...

I am experiencing an issue with the PUT method on my API as it is not correctly setting the req.body data

Below is the code snippet for implementing the PUT method: [/api/[id].ts] case "PUT": try { const user = await UserModel.findOneAndUpdate( { _id: id, }, { $set: req.body, ...

Is there a way for me to define the type of a prop based on the type of another prop?

I'm not entirely certain how to phrase this inquiry, or which terminology to employ, so I'll do my best in presenting it. My intention is to develop a component that functions on an array of elements and triggers a render function for each eleme ...

Tips for automatically scrolling the Google Maps view in a React application

After implementing the google-map-react package, I have designed a TypeScript MapView component with the following code snippet. export function MapView<I extends Mappable>({ getData }: MapViewProps<I>): JSX.Element { const [mapZoom, setMapZo ...

Quick way to specify type for Observable in Typescript

Exploring Shortcut Declarations When working with TypeScript, I often take a shortcut when declaring object shapes. Instead of creating an interface first and then specifying that the object conforms to that type, I simply do: object: { fizz: boolean, buz ...

Removing Angular Template space highlights in WebStorm can be done easily with a few simple steps

Is there a way to remove space highlights in Angular / TypeScript using WebStorm 2019? https://i.stack.imgur.com/vfudR.jpg Many thanks, Sean ...

When using Angular, a service can be declared in the viewProviders of the parent component and then accessed in the viewProviders of the child

Imagine a scenario where there is a parent component called AppComponent, a directive named MyDirective, and a service named SimpleService. In this case, MyDirective is utilized in the template of AppComponent and injects SimpleService using the Host deco ...

Steps for utilizing an `<a>` link tag to submit a form in Angular 4

Is there a way to retrieve the selected option in this form from the other side when clicking a link? <form (ngSubmit)="onSubmit(x)"> <input type="radio" id="radioset3" name="radioset" [checked]="x==0"> <input type="radio" id="radio ...

Is there a way to achieve this using a fresh and sleek typescript assertion function?

Presented below is the snippet of code: type Bot = BotActive | BotInactive; class BotActive { public readonly status = "active"; public interact() { console.log("Hello there!"); } } class BotInactive { public ...

Utilize puppeteer and web-vitals in NextJS to retrieve the web performance metrics of a website

I'm currently working on a basic tool in NextJS that uses puppeteer to fetch web vitals data from a given URL. However, I'm facing an issue where the results are not being printed out. What could be causing this problem? const browser = await pup ...