如何在vscode中使用jsdoc在包装函数中正确获取返回值的推断类型? 用于发送请求的包装器预期我们在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能够推断出“结果”的类型为string [],甚至可以从api客户端给我进行描述(“ 3个首字母”)。

但不是,它将在末尾给出any的类型。

我们在vscode中得到的东西

如果我们遵循vscode挑选的类型,我们可以看到它“一点一点地丢失了类型”,直到没有剩余。

  1. 为api客户端选择了完整的类型说明。

Full type description in the api client

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

The type is known in the handler definition but we lost the client value description

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

We lost the type information completely

解决方法

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块不会返回类型T的值(由于未键入错误,它会返回any)。

如果写了@returns,则可以省略request

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

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

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

enter image description here