Determining the parameter type of an overloaded callback: A comprehensive guide

I am currently working on creating a type-safe callback function in TypeScript with a Node.js style. My goal is to define the err parameter as an Error if it exists, or the data parameter as T if not.

  1. When I utilize the following code:
export interface SafeCallback<T> {
    (err: unknown): void;
    (err: undefined, data: T): void;
}

const subscribe = <T>(callback: SafeCallback<T>) => {
    let result: T;
    try {
        // result = something
    } catch (e) {
        callback(e);
        return;
    }

    callback(undefined, result);
};

subscribe<{id: string}>((err, data?) => {
    if (!err) {
        console.log(data.id);
    }
});

The error message states that 'data' is of type 'unknown'.

  1. If I remove the question mark from the data, I receive the following error:
    Argument of type '(err: undefined, data: { id: string; }) => void' is not assignable to parameter of type 'SafeCallback<{ id: string; }>'

Even after attempting to define err: Error in the first overload for both cases, the issue remains unresolved.

Are there any other approaches I should consider?

Thank you!

Answer №1

Is it possible to use a conditional type?

export type SafeCallback<T> = {
    <errorType>(err: errorType, data: errorType extends undefined ? T : null): void;
};


const subscribe = <T>(callback: SafeCallback<T>) => {
    let result: T;
    try {
      // logic for result
    } catch (e) {
        callback(e, null);
        return;
    }

    callback(undefined, result);
};

subscribe<{ id: string }>((err, data) => {
    if (data !== null) {
        console.log("data  = " + data.id);
    } else {
        console.log("err = " + err);
    }
});

Edit: I noticed @jcalz's response. I'm incorporating something from it:

export interface SafeCallback3<T> {
    <errorType>(...args:( errorType extends undefined ? [err: undefined, data: T] : [err: errorType] )): void;
}

This helps prevent casting errors in the catch block.

const subscribe3 = <T>(callback: SafeCallback3<T>) => {
    let result: T;
        try {
        // ...
        } catch (e) {
            callback(e);
            return;
    }

    callback<undefined>(undefined, result);
};
    
subscribe3<{ id: string }>((...args) => {
  const [err, data] = args;
  if (!err) {
    console.log(data.id);
  } else {
    err.message
  }
});

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

What is the reason behind Angular 2's choice to implement the .ts file extension?

What is the significance of using the .ts file extension in Angular 2? ...

Is it advisable for a component to handle the states of its sub-components within the ngrx/store framework?

I am currently grappling with the best strategy for managing state in my application. Specifically, whether it makes sense for the parent component to handle the state for two subcomponents. For instance: <div> <subcomponent-one> *ngIf=&qu ...

suspicion arises that the argument is not correctly referencing the appropriate variables

I am trying to grasp the situation happening here. I have two variables activeToInactive and inactiveToActive which I increase whenever a status is updated. Here's my code snippet: Counter Service: export class CounterService { // Initial States ...

Error in TypeScript when utilizing an Enum as a string

Attempting to include a string enum in my Angular 2 project resulted in an error during the npm project startup: ERROR in e:/projects/dbtool-fullstack/dbtool-client/src/app/shared/models/full-m odels/enums/Sex.ts (2,10): Type '"Male"' is not ass ...

Is it possible to simultaneously update two entities using a single endpoint?

In order to update data in two different entities with a @OneToOne relationship between UserEntity and DetailsEntity, I need to create a function in my service that interacts with the database. Here are the entity definitions: UserEntity @Entity() export ...

Implementing a Typescript directive in AngularJS to create a class

After using AngularJS for quite some time, I decided to explore Typescript. I managed to convert most of my Angular code to Typescript and found it beneficial, especially when working with services. However, I am struggling to convert the following direc ...

Tips for identifying the load window in Ionic 2 RC3 Angular 2

In the various services that I am using, I implement a method to load content. Each service has its own loadController to display a loading window. How can I detect if a loading window already exists in order to prevent showing a new one? *Please note: I ...

Is there a way to access the filtered or organized rows in the Quasar Q-Table?

I have encountered a roadblock in my project. Despite installing Quasar version 2.0.0, I realized that it lacks a property to access the filtered or sorted rows. Previous versions of q-table had a computedRows property which was missing in the latest ver ...

Incorporate an external library

I am currently facing a challenge in my angular2 project where I need to import a 3rd party library. Here are the steps I have taken so far: ng new myproject npm install --save createjs-easeljs npm install @types/easeljs However, I am stuck at this poin ...

Testing attributes and props with React Testing Library

Currently, I am in the process of developing a React application using TypeScript. For creating components, I rely on material-ui and for unit testing, I make use of react-testing-library. Specifically, I am working on designing a wrapper for the Grid com ...

Diverse Range of Exports Available in React Component Library

I have been working on developing a component library consisting of multiple independent components. My objective is to enable users to easily import and use these components in their projects, similar to the following: import One from 'component-lib ...

Best practices for safely handling dynamic keys in Typescript

I am searching for a secure method to create keyed objects in this manner: interface Types { RED: 'RED'; BLUE: 'BLUE'; GREEN: 'GREEN'; } type TypeKeys = keyof Types; const COLORS: Types = { RED: 'RED', B ...

Is it better to store data individually in localStorage or combine it into one big string?

When it comes to keeping track of multiple tallies in localStorage, one question arises: Is it more efficient to store and retrieve several small data points individually or as one larger chunk? For example: localStorage.setItem('id1', tally1); ...

Error: Code cannot be executed because the variable "sel" has not been defined in the HTML element

Every time I try to click on the div, I encounter an error message stating 'Uncaught ReferenceError: sel is not defined at HTMLDivElement.onclick' I am currently developing with Angular 8 and this error keeps popping up. I have read through simil ...

Can a generic type be utilized to instantiate an object?

In my code, I have a class named Entity as shown below: class Entity { constructor(readonly someValue: string) {} someFunction() {} } Now, I am trying to create a class that will handle these entities and be able to create instances of them. In or ...

Struggling with setting up Angular Material and SCSS configuration in my application -

Hey there, I encountered an error or warning while trying to launch my angular app. Here's the issue: ERROR in ./src/styles/styles.scss (./node_modules/@angular-devkit/build- angular/src/angular-cli-files/plugins/raw-css- loader.js!./n ...

Ways to increase the number of responses in an Express app after the initial response

In order to comply with the Facebook messenger API requirements, a 200 response must be sent immediately upon receiving the webhook request on my server, within 20 seconds. However, this process may take longer than the execution time of other middleware f ...

What is the process for assigning a custom React component as the Type for a prop in another component?

Currently, I am working on a customized GenericModal component and would like to include an array of my ModalText components as props in the GenericModal for display purposes. I want to specifically define the type of prop being passed, rather than using s ...

Guide on how to switch a class on the body using React's onClick event

There's a button in my code that triggers the display of a modal-like div element. When this button is clicked, I aim to apply a class to the body element; then when the close button is clicked, I'll remove this class. I'm looking for guid ...

Issues arise when attempting to enforce type-safety in TypeScript while using the JSON.parse

Is it possible that type-safety is compromised in TypeScript when dealing with JSON parsing? I should be triggering an error, but I'm not: interface Person { name: string } const person: Person = somePossibleFalsey ? JSON.parse(db.person) : undefi ...