如何在 vscode 中使用 jsdoc 正确获取包装函数中返回值的推断类型?

How to properly get inferred types of returned values in a wrapper function with jsdoc in vscode?

这里有一些代码(经过简化)可以更好地理解:

发送请求的包装器

async function request (handler) {
  // common stuff
  try {
    const result = await handler()
    return result || true
  }
  catch (err) {
    doSomethingWithError(err)
    return err
  }
  finally {
  // common stuff
  }
}

/**
 * Imagine a simple service / api client
 */
const someApiClient = {
  /**
   * @returns {Promise<string[]>} 3 first letters
   */
  async getSomeData () {
    return ['a', 'b', 'c']
  }
}

/**
 * Just a function or method using the api client, that has types declared
 */
async function fetchMeSomeDataHandler () {
  return someApiClient.getSomeData()
}

const result = await request(() => fetchMeSomeDataHandler())

预计

在这里,我希望 vscode / jsdoc 推断“结果”的类型是字符串[],甚至给我 api 客户端的描述(“3 个首字母” ).

但不是,最后会给出一个any的类型

我们在 vscode

中得到了什么

如果我们按照 vscode 拾取的类型,我们可以看到它正在“逐渐丢失类型”,直到什么都没有。

  1. 为 api 客户端选择的完整类型描述。

  1. 类型在处理程序定义中已知,但我们丢失了客户端值描述(3 个首字母)。

  1. 我们完全丢失了最终结果的类型信息

VS Code 会尝试根据函数参数的用法来推断函数参数的类型。一个简单的例子是:

function foo(a) {
    return a.b;
}

foo({ b: 3 })

这导致 foo 具有签名 function foo(a: any): any。您的代码是此限制的一个更复杂的示例。

修复方法是在 request:

上显式注释参数类型
/**
 * @template T
 * @param {() => Promise<T>} handler 
 * @return {Promise<T>}
 */
async function request(handler) {
   ...
}

在这种特定情况下,我们还需要显式 @returns,因为 catch 块不 return 类型 T 的值(它 return 是 any 因为错误是无类型的)。​​

你可以省略 @returns 如果 request 写成:

/**
 * @template T
 * @param {() => Promise<T>} handler 
 */
async function request(handler) {
    // common stuff
    const result = await handler()
    return result
}

因为 VS Code 可以推断 return 类型的函数(但请记住,显式类型在许多情况下很有用,尤其是对于可能 return 多种不同类型的函数)

添加显式类型后,result 应该具有正确的类型: