как исправить универсальную функцию, которая обрабатывает асинхронные функции

#typescript #generics #types

#typescript #универсальные #типы

Вопрос:

Я хочу создать универсальную функцию, которая принимает асинхронную функцию, выполняет ее и улавливает ошибку, если предоставленная функция сталкивается с какими-либо проблемами.

поскольку я работаю на javascript, я смог создать следующую функцию, которая делает именно это. но я хотел улучшить ее с помощью дженериков и не смог этого сделать

этот код работает так, как ожидалось. но я не получаю никакого типа в своем аргументе ‘msg’.

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

итак, я попытался написать следующее

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

к сожалению, мой код не работает, и IDE по-прежнему сообщает мне, что сообщение имеет тип any неявно в следующем коде

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

(возвращает : Parameter 'msg' implicitly has an 'any' type. )

но выделение botAsyncHandler показывает следующее:

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

Похоже, это то, что я хочу. Мне любопытно узнать, где я ошибаюсь

Комментарии:

1. Примечание о вашей реализации JavaScript: если вы знаете, fn есть async , нет смысла Promise.resolve(fn(arg)) . Если вы не знаете, fn есть async (например, это может быть, а может и не быть), вы не будете перехватывать ошибки из него таким образом, если он синхронный.

2. @T.J.Crowder вся цель функции — перехватить отклонение обещаний и обработать их. Это всегда асинхронно. Promise.resolve(fn(arg)) был просто для согласованности. функция не должна ничего возвращать. итак, пустота

3. Согласованность с чем ?

4. @T.J.Crowder хорошая мысль. когда я писал это, функция всегда должна была возвращать обещание, и я хотел, чтобы код был понятным

Ответ №1:

Function Тип бесполезен. Не используйте ее. Тип fn параметра примерно такой: (msg: T) => Promise<void> . Или вы можете решить принять синхронные функции, которые возвращают void : (msg: T) => void | Promise<void> .

Вы могли бы написать:

 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>'
  

И я не могу протестировать, но ваш код должен работать так, как ожидалось:

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

Ответ №2:

Из вашего примера использования:

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

и, например, JavaScript, похоже, что вы пытаетесь создать функцию, которая будет возвращать функцию, которая при вызове вызывала бы оригинал, но обрабатывала ошибки из него. Самый простой способ сделать это — просто написать async функцию с try / catch в ней. Версия JavaScript:

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

добавление к ней аннотаций типов с обобщениями:

 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);
  }
};
  

Это предполагает, что функция должна объявлять один формальный параметр. <a rel="noreferrer noopener nofollow" href="https:///www.typescriptlang.org/play/index.html#src=type AsyncHandler = (arg: T) => {};
const botAsyncHandler = (fn: AsyncHandler) => async (msg: T) => {
try {
fn(msg);
} catch (error) {
console.log(error.message);
}
};

botAsyncHandler((str:string) => str);
botAsyncHandler((n:number) => n);
botAsyncHandler(() => { }); // Fails because function requires argument» rel=»nofollow noreferrer»>Жить на игровой площадке.

Но я не уверен, что добавление параметра типа дает вам что-нибудь здесь, учитывая, что вы используете <T extends any> .

Комментарии:

1. отлично. это работает. но другой ответ, похоже, имеет лучшие типизации

2. @Omid — Действительно. Если бы это был я, я бы просто предложил изменения, но….