首页 > 解决方案 > 如何调用存储在变量中的异步函数?

问题描述

所以我有以下问题:

给定一个键,我将从字典中获取一个函数,该函数可以是异步函数或普通函数。但是当我将 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)
}

标签: typescriptasync-await

解决方案


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


问题是func instanceof Promise检查func它本身是否是 a 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);

推荐阅读