【问题标题】:How can I call an async function that is stored in a variable?如何调用存储在变量中的异步函数?
【发布时间】:2020-09-30 11:43:51
【问题描述】:

所以我有以下问题:

给定一个键,我将从字典中获取一个函数,该函数可以是异步函数或普通函数。但是当我将 await 关键字放在 func 之前,编译器会抱怨:

TS2349:无法调用其类型缺少调用签名的表达式。类型“Promise”没有兼容的调用签名。

我该如何解决这个问题?开关将是唯一的解决方案?

简单示例:

function example(aux: string){
    return string
}

function async main(key, ...args): Promise<Boolean>{
    dictionary = {
        "example": example
    }

    let func = dictionary[key]

    if (func instanceof Promise) { // If the function is a promise we wait
          let result = await func(...args) //<-- PROBLEM HERE
       } else {
          let result = func(...args)
       }
    }

    return result

此处为完整示例:

export enum ValidatorsTypes {
  EMAIL = 1,
  EMAIL_IS_UNIQUE = 2
}

export function validEmail (text: any) {
  const pattern = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
  return pattern.test(text) || 'Invalid e-mail.'
}

export async function isEmailUnique (text: any): Promise<boolean> {
  let response = await UserService.list(1, 1, { 'email': text })

  // if the number of matches is 0, then is unique
  return response[1] === 0
}

export async function isAnswerValid (validatorsTypes: Array<ValidatorsTypes>, ...args: any) : Promise<boolean> {
  let availableValidators = {
    [ValidatorsTypes.EMAIL]: validEmail,
    [ValidatorsTypes.EMAIL_IS_UNIQUE]: isEmailUnique
  }

  let results = []

  for (let rule of validatorsTypes) {
    let func = availableValidators[rule]

    if (func instanceof Promise) { // If the function is a promise we wait
      let result = await func(...args) //<-- PROBLEM HERE
      results.push(result)
    } else {
      results.push(func(...args))
    }
  }

  return !results.some(v => v === false)
}

【问题讨论】:

  • Aron 提供了解决方案。我只想说,我认为您应该决定是否真的要同步运行所有规则(即,在当前可能是异步的规则完成之前不要继续前进)。如果是这样,我建议您在返回错误的情况下尽早返回(然后您可以避免存储此结果数组。否则,我建议您“同时”发送所有内容,或者它们都返回正确,或者一个返回 false,您返回 false 并取消所有其他事情(如果可以的话)。

标签: typescript async-await


【解决方案1】:

请参阅下面的编辑以获得更简单的解决方案


问题是func instanceof Promise 检查func 本身是否是Promise,而不是检查是否返回promise 的函数。

如果您想根据func 的返回值做不同的事情,您需要检查instanceof Promise 的返回值

所以这样的事情会起作用

const result = func(...args);
// const result: true | 'Invalid e-mail.' | Promise<boolean>

if (result instanceof Promise) { // we check if result is a Promise
  const awaitedResult = await result; // if result is a promise we await it
  // const awaitedResult: boolean

  results.push(awaitedResult);
} else {
  results.push(result); // otherwise we just push the value immediately
}

编辑

正如@Countingstuff 指出的那样,等待非承诺没有害处,因此我们可以通过等待func 返回的任何内容来简化整个事情,根本不需要检查任何内容是否是承诺!

const func = availableValidators[rule];
// const func: ((text: any) => true | "Invalid e-mail.") | ((text: any) => Promise<boolean>)

const result = await func(...args);
// const result: boolean | 'Invalid e-mail.'

results.push(result);

【讨论】:

  • 等待不是承诺的东西没有坏处,所以实际上我认为你可以删除整个条件。
【解决方案2】:

当你从字典中取出你的函数时,它有一个Any 类型。您有 2 个选项,首先您可以转换为 Function 例如

let func = dictionary[key] as Function;

或者不要使用object 作为您的字典,而是使用Map&lt;string, Function&gt; 例如

const dict = new Map<string, Function>();
dict.set("example", this.example);
let func = dict.get('example');

拥有func后,只需await func()即可,无需if检查

【讨论】:

  • 这如何回答这个问题?
  • 您在 op 的问题中看到了 //&lt;-- PROBLEM HERE 的评论。这就是回答问题的方式。
  • 问题是我们如何根据函数是否返回一个promise来有条件地等待一个函数。您的回答对此有何帮助?
  • 这不是问题所在。问题是TS2349: Cannot invoke an expression whose type lacks a call signature. Type 'Promise ' has no compatible call signatures. How could I solve this issue?
猜你喜欢
  • 2020-07-28
  • 2021-04-20
  • 1970-01-01
  • 2022-11-26
  • 1970-01-01
  • 2020-03-09
  • 2011-04-22
  • 1970-01-01
  • 2020-12-20
相关资源
最近更新 更多