2

I want to create a generic function that accepts an async function, executes it and catches the error if the provided function encounters any problems.

since I come from a javascript background, I was able to create the following function that does just that. but I wanted to improve it using generics and failed to do so

this code works as expected. but i don't get any type on my 'msg' argument.

const botAsyncHandler = (fn:Function) => (msg: any) => {
  Promise.resolve(fn(msg)).catch(error => {
    console.log(error.message);
  });
};

so i tried to write the following

const botAsyncHandler = <T extends any>(fn:Function)=> (msg: T) => {
  Promise.resolve(fn(msg)).catch(error => {
    console.log(error.message);
    console.log('here');
  });
};

sadly my code does not work, and IDE still tells me that msg is of type any implicitly on the following code

bot.on('photo', botAsyncHandler(async msg => {}))

( returns : Parameter 'msg' implicitly has an 'any' type.)

but highlighting the botAsyncHandler shows the following:

botAsyncHandler<TelegramBot.Message>(fn: Function): (msg: TelegramBot.Message) => void

Which seems like what I want. I curious to know where I'm going wrong

4
  • Side note about your JavaScript implementation: If you know fn is async, there's no point to Promise.resolve(fn(arg)). If you don't know fn is async (e.g., it may or may not be), you won't catch errors from it that way if it's synchronous. Commented Apr 7, 2019 at 16:00
  • @T.J.Crowder the whole goal of the function is to catch promise rejection and handle them. It's always async. Promise.resolve(fn(arg)) was just for consistency. the function is not supposed to return anything. so void Commented Apr 7, 2019 at 16:06
  • 1
    Consistency with what? Commented Apr 7, 2019 at 16:06
  • @T.J.Crowder good point. when I wrote it,the function always was supposed to be return a promise and i wanted the code to be clear Commented Apr 7, 2019 at 16:11

2 Answers 2

3

The Function type is useless. Do not use it. The type of the fn parameter is something like: (msg: T) => Promise<void>. Or you can decide to accept synchronous functions that returns void: (msg: T) => void | Promise<void>.

You could write:

const botAsyncHandler = <T>(fn: (msg: T) => void | Promise<void>) => async (msg: T) => {
    try {
        await fn(msg);
    } catch (err) {
        console.log(err.message);
    }
};

const onString = (msg: string) => {};
const fn = botAsyncHandler(onString);
// Here, the type of 'fn' is: '(msg: string) => Promise<void>'

And I can't test but your code should work as expected:

bot.on('photo', botAsyncHandler(async msg => {}))
Sign up to request clarification or add additional context in comments.

Comments

1

From your example usage:

bot.on('photo', botAsyncHandler(async msg => {}))

and JavaScript example, it looks like you're trying to create a function that will return a function, which when called would call the original but handling errors from it. The simplest way to do that is just to write an async function with a try/catch in it. JavaScript version:

const botAsyncHandler = (fn) => async (msg) => {
  try {
    await fn(msg);
  } catch (error) {
    console.log(error.message);
  }
};

adding type annotations w/generics to it:

type AsyncHandler<T> = (arg: T) => {};
const botAsyncHandler = <T extends any>(fn: AsyncHandler<T>) => async (msg: T) => {
  try {
    await fn(msg);
  } catch (error) {
    console.log(error.message);
  }
};

That assumes the function must declare one formal parameter. Live on the playground.

But I'm not sure adding a type parameter buys you anything here, given you're using <T extends any>.

2 Comments

great. it works. but the other answer seems to have better typings
@Omid - Indeed. If it'd been me, I'd've just suggested the changes, but....

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.