What is the best way to create an overload signature for a function that could potentially receive either 1 or 2 arguments when called?

Trying to define the signature for a function that can be called with either 1 or 2 arguments, encountering an error stating that the type of the function with 2 arguments is not compatible with the defined type.

The specified type:

type Response = {
  status: string;
  result: object;
}

export interface CallbackFunction {
  (response: Response): void;
  (error: Error | null, response?: Response): void;
}

// Example code triggering the error

// OK
// res: Response | Error | null
export const fn: CallbackFunction = (res) => {
  // ...
};

// Error
// Type '(err: Error | null, res: Response | undefined) => void' is not assignable to type 'CallbackFunction'.
export const fn2: CallbackFunction = (err, res) => {
  // ...
};

// Error
// Argument of type '{ status: string; result: {}; }' is not assignable to parameter of type 'Error'
fn({ status: 'Test', result: {} })

The library in use invokes this function with a single argument if the timeout option is not explicitly set, and with two arguments if the timeout occurs - first being an error on timeout (or null), and second being the result.

Though not an ideal design, unable to modify as it's part of a third-party library.

Answer №1

It is important to note that the first overload of the CallbackFunction interface does not expect a second parameter, which can be made optional to align with the second overload:

export interface CallbackFunction {
  (response: ExampleResponse, _?: never): void;
  (error: Error | null, response?: ExampleResponse): void;
}

By adjusting it accordingly, you will notice how effectively it operates as demonstrated in this Playground.

Answer №2

The clarity of what can be modified in the code above is questionable. Let's assume that you have the freedom to modify the type declaration and the initial handler.

If you wish, you can update your type definition like this:

type CallbackFunction =
    ((response: Response) => void) |
    ((error: Error | null, response?: Response) => void);

This defines an union of two potential function overloads. However, there’s ambiguity present in the first usage example: should it follow the form with all parameters or the one where a parameter is unnecessary?

export const fn: CallbackFunction = (res: ???) => {
    //
};

To resolve this, adjust the code slightly for smooth operation:

export const fn: CallbackFunction = (res: Response) => {
    //
};

// Error
// Type '(err: Error | null, res: Response | undefined) => void' is not assignable to type 'CallbackFunction'.
export const fn2: CallbackFunction = (err, res) => {
    // ...
};

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

Having trouble getting elastic-apm-node to function with Webpack, Typescript, and ES6?

While working with a TypeScript setup using webpack and babel, I encountered an issue when trying to include elastic-apm-node. Despite having the settings in environment variables, I still faced errors. import * as apm from 'elastic-apm-node/start&ap ...

Tips for adding a new property to an array object in TypeScript using a condition

Here is an array object that I have: arr = [ { Name: "ABC", Age: 20}, { Name: "XXX", Age: 15} ]; In Typescript, I am looking to dynamically add a new property called "Flag" with a value of 1 only if the Age is greater than 15. Can someone suggest ...

Encountering issue while resolving flux/utils in webpack

My TypeScript OS project is in the process of being migrated to webpack, Unfortunately, I am currently facing a build error: ERROR in ./src/store/GigaStore.ts Module not found: Error: Cannot resolve module 'flux/utils' in /home/erfangc/GigaGrid ...

Having trouble updating properties of child components in Angular

I have a data filtering functionality where I enter values in a filter popup and successfully retrieve results. I then store this data in local storage to retain it when navigating back from another page. However, upon returning to the filter component, I ...

Utilizing React Bootstrap with TypeScript for Styling Active NavItem with Inline CSS

Is it possible to change the background color of the active NavItem element to green using inline CSS in React Bootstrap and React Router Dom? I am currently using TypeScript 2.2 and React. If not, should I create a CSS class instead? Here is the code sni ...

Sorting JSON arrays in Typescript or Angular with a custom order

Is there a way to properly sort a JSON array in Angular? Here is the array for reference: {"title":"DEASDFS","Id":11}, {"title":"AASDBSC","Id":2}, {"title":"JDADKL","Id":6}, {"title":"MDASDNO","Id":3}, {"title":"GHFASDI","Id":15}, {"title":"HASDFAI","Id": ...

Discovering the position of an element within an array and leveraging that position to retrieve a corresponding value from a separate array

const STATE = ["TEXAS","CALIFORNIA","FLORIDA","NEW YORK"] const STATE_CODE = ["TX","CA","FL","NY"] With two arrays provided, the first array is displayed in a dropdown menu. The challenge is to retrieve the corresponding state code from the second array ...

Issue encountered when trying to export a function that returns a class: The exported variable either contains or is utilizing a private name

Encountered an issue Error TS4025: Exported variable 'UserApiClientModule' has or is using private name 'UserApiClient'. Here's the code causing the error: export var UserApiClientModule = { fromConfiguration: (configuration ...

propagate the amalgamation of tuples as an argument

I'm working with a function that returns a union type of tuples. I need to pass this return value to another function that can accept all its forms using the spread operator .... type TupleUnion = readonly [number, number] | readonly [number, number, ...

Create a function in JavaScript that is able to accept a variable number of objects as arguments

I have a good grasp of how to pass infinite parameters in a function in JavaScript. But what about accepting any number of objects as parameters in a function? This is my current implementation: function merge<T>(objA: T, objB: T){ return Object. ...

Can you please identify the TypeScript type associated with the return value of the match() method in String prototype?

I need help with creating a Regex in JavaScript const pattern = /S(\d+)E(\d+)/; // identifying characters between "S" and "D" const result = 'SE01E09'.match(pattern); How should I declare the result variable? I have attempted various ...

Firebase Promise not running as expected

Here is a method that I am having trouble with: async signinUser(email: string, password: string) { return firebase.auth().signInWithEmailAndPassword(email, password) .then( response => { console.log(response); ...

Is it possible to import both type and value on the same line when isolatedModules=true?

Did you know with Typescript, you can do type-only imports? import type { Foo } from "./types" If the file exports both types and values, you can use two separate import statements like this: import type { Foo } from "./types"; import ...

Output in Typescript for the chosen option

A message can be sent based on the user's choice of either Now or Later. If the user selects Now, the message will be sent immediately. If Later is chosen, a date format option needs to be created for setting a future date. <label for=""& ...

Retrieve all objects of the selected value using Angular autocomplete when an option is selected

I am currently working with an autocomplete component. I am passing an array of objects and would like to retrieve all item information (option) when an option is selected, not just the field value (option.name). <form class="example-form"> ...

Navigating through nested JSON Objects for dropdown functionality in Angular 6 - a step-by-step guide

Currently, I am facing a challenge in Angular 6.0 where I am trying to use HttpClient to iterate through JSON data retrieved from a local file within my assets folder. Below is the sample JSON Data: [{ "configKey": [{ "user1": [{ ...

Sending data using jQuery to a web API

One thing on my mind: 1. Is it necessary for the names to match when transmitting data from client to my webapi controller? In case my model is structured like this: public class Donation { public string DonorType { get; set; } //etc } But the f ...

Using Jest functions as object properties results in undefined behavior

I am faced with a challenge in my class where I need to mock an object along with its properties intercept(context: ExecutionContext) { const response = contect.switchToHttp().getResponse() // the chain that needs to be mocked if (response.headersSent ...

Prevent saving the file until all the categories have been chosen

We have recently updated our file list by adding a new file category column. Our aim now is to prevent users from saving the form until a category has been assigned to each file. However, I am unsure how to check for the presence of a value in each file ...

Issue: The element 'app-header' is unrecognized in Angular 2

Here is a breakdown of my folder structure. app - common - header header.component.css header.component.html header.component.ts - footer footer.component.css footer.component ...