typescript - How to define the correct return type in Higher-Order Functions - Stack Overflow

admin2025-04-20  1

I'm using Next.js, Auth.js and mongoose, my problem is I wanted to wrap all my controllers with a wrapper/helper function called withDBConnection to save me time not establishing a connection with the db each time, it takes the controller and returns it after connecting:

type Controller <Args extends any[]> = (...args: Args) => any;
export const withDBConnection = <Args extends any[]> (Controller:Controller<Args>):(...args:Args) => Promise<any> => {
    return async (...args: Args) => {
    try {
      await dbStartConnection();
      Controller(...args);
    } catch (error) {
      console.log("inside withDBConnection catch block");
      console.log((error as AppError).message);
    }
  };}

an example of using the helper function:

export const getUser = withDBConnection( async(email: string) => {
  const user = await Auth.find({discordEmail: email});
  console.log("getUser", user);
  return user;
});

but the controller doesn't return the value, which is user, I can't use it in the Auth.js signIn() callback:

const isExist = await getUser(user.email);

isExist is always undefined so the app goes to createNewUser controller:

if(!isExist) await createNewUser(user);

I tried to change the return type from any to mongoose type Document in both type Controller and withDBConnection but that made the ts complain about the email: string

I'm using Next.js, Auth.js and mongoose, my problem is I wanted to wrap all my controllers with a wrapper/helper function called withDBConnection to save me time not establishing a connection with the db each time, it takes the controller and returns it after connecting:

type Controller <Args extends any[]> = (...args: Args) => any;
export const withDBConnection = <Args extends any[]> (Controller:Controller<Args>):(...args:Args) => Promise<any> => {
    return async (...args: Args) => {
    try {
      await dbStartConnection();
      Controller(...args);
    } catch (error) {
      console.log("inside withDBConnection catch block");
      console.log((error as AppError).message);
    }
  };}

an example of using the helper function:

export const getUser = withDBConnection( async(email: string) => {
  const user = await Auth.find({discordEmail: email});
  console.log("getUser", user);
  return user;
});

but the controller doesn't return the value, which is user, I can't use it in the Auth.js signIn() callback:

const isExist = await getUser(user.email);

isExist is always undefined so the app goes to createNewUser controller:

if(!isExist) await createNewUser(user);

I tried to change the return type from any to mongoose type Document in both type Controller and withDBConnection but that made the ts complain about the email: string

Share Improve this question edited Mar 2 at 14:40 jonrsharpe 122k30 gold badges268 silver badges476 bronze badges asked Mar 2 at 14:02 MaryaMarya 1728 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 3

The main issue was that Controller(...args); is called without returning its result, causing the wrapped function to return undefined. The following code properly awaits and returns the result from Controller

type Controller<Args extends any[]> = (...args: Args) => Promise<any>;

export const withDBConnection = <Args extends any[]>(
  Controller: Controller<Args>
): ((...args: Args) => Promise<any>) => {
  return async (...args: Args) => {
    try {
      await dbStartConnection();
      return await Controller(...args); 
    } catch (error) {
      console.log("inside withDBConnection catch block");
      console.log((error as AppError).message);
      throw error; 
    }
  };
};

Edit: Here Controller(...args) is executed, and since it's an async function, it returns a Promise immediately. Immediately , the execution of withDBConnection continues, and the function returns a Promise that resolves to undefined, because there's no explicit return statement.

But by return await Controller(...args) ensures that: The execution of withDBConnection waits for the async operation in Controller to complete.

If you are interested in learning concurrency you definitely need to check out

  • "Async JavaScript: Build More Scalable Applications with Less Code" by Trevor Burnha
  • Multithreaded JavaScript: Concurrency Beyond the Event Loop
转载请注明原文地址:http://conceptsofalgorithm.com/Algorithm/1745120980a286143.html

最新回复(0)