【问题标题】:How to annotate Express middlewares with JSDoc?如何使用 JSDoc 注释 Express 中间件?
【发布时间】:2015-01-31 17:29:39
【问题描述】:

我正在尝试记录 Express 中间件,但 WebStorm 中的内置验证工具告诉我在以下 JSDoc 块中分配的类型不正确:

/**
 * My middleware.
 *
 * @param {Object} req
 * @param {Object} res
 * @param {Function} next
 * @return {Object}
 */
exports.show = function(req, res, next) {
    ...
};

在 Express 资源中,我没有找到任何 @typedefs 来帮助我。另外,我想避免像@param {*} 这样的事情。

使用 JSDoc 记录 Express 中间件的正确方法是什么?感谢您的帮助。

【问题讨论】:

  • 您是否尝试删除 @return 行?特快路线通常不会返回任何东西。
  • Webstorm 应该提示你错误是什么,不是吗?
  • 您如何将此中间件添加到您的应用中?
  • 在@return {Object} 之后添加一个描述,这在过去确实为我解决了这个问题,或者您可以使用 eslint jsdoc 验证来判断发生了什么问题

标签: javascript express webstorm jsdoc


【解决方案1】:

reqresnext都是对象,中间件一般不返回,所以可以使用下面的。

/**
 * My Middleware
 * @name MyMiddleWare
 * @function
 * @param {Object} req
 * @param {Object} res
 * @param {Object} next
 */

【讨论】:

  • 如果函数没有显式返回值,它会隐式返回undefined。根据您遵循的风格指南,这可能会或可能不会使用@return 标记显式调用:@return {undefined}。例如,Google 的 Closure Compiler 样式指南禁止它。 developers.google.com/closure/compiler/docs/…
  • Object 表示any
【解决方案2】:

您唯一需要更改的是@param {Object} 旁边的@param {Function}。此外,@return 应该描述函数返回的内容;例如,(Object, Array) 或组合 ({Object|Null})

【讨论】:

  • 中间件通常返回undefined - 当函数没有返回值时,许多开发人员将返回标签视为可选或不正确的。
【解决方案3】:

首先,我们同意中间件是函数;通常不需要特殊的类型声明。除此之外,中间件往往是高度解耦的——模块化——这意味着@module 标签通常是适用的(这在您运行 jsdoc 时会产生很好的效果)。

/**
 * Description of my middleware.
 * @module myMiddleware
 * @function
 * @param {Object} req - Express request object
 * @param {Object} res - Express response object
 * @param {Function} next - Express next middleware function
 * @return {undefined}
 */

根据您的样式指南,返回标签是可选的,因为中间件不返回值。最后,与 Nick 和 mmm 声称的相反,next 参数是一个函数。

http://expressjs.com/en/guide/using-middleware.html

中间件函数是有权访问请求的函数 对象(req)、响应对象(res)和下一个中间件 在应用程序的请求-响应周期中起作用。 next 中间件函数通常由名为 next 的变量表示。

next 不是一个花哨的 Express 内部混合物; Express 将请求、响应和堆栈中的下一个中间件函数传递给每个中间件函数,如下所示:

mw1 = function(req, res, next){}.bind(undefined, req, res, mw2)
mw2 = function(req, res, next){}.bind(undefined, req, res, mw3)

nextmw1范围内的值为mw2

【讨论】:

    【解决方案4】:

    你不仅可以 JsDoc 的参数类型和描述,还可以他们的预期成员。

    /**
     * 
     * @module myMiddleware
     * @function
     * @param req {Object} The request.
     * @param res {Object} The response.
     * @param req.params.foo {String} The foo param.
     * @param req.query.bar {String} The bar query.
     * @param req.body {Object} The JSON payload.
     * @param {Function} next
     * @return {undefined}
     */
    function foo(req, res, next){
    }
    

    【讨论】:

    【解决方案5】:

    使用肯定类型

    1. 安装快递类型npm install --save-dev @types/express
    2. 像往常一样使用 e.Response @param {e.Response} res

    更多类型

    • 在文件/node_modules/@types/express/index.d.ts
    • Responsee.Response,因为:

    ... declare namespace e { ... export interface Response extends core.Response { } ...

    网络风暴

    通过设置 > 语言和框架 > Javascript > 库 > @types/express 安装类型

    【讨论】:

      【解决方案6】:

      你可以用

      记录你的中间件
      const express = require("express");
      
      /**
       * @param {express.Request} req
       * @param {express.Response} res
       * @param {express.NextFunction} next
       */
      function (req, res, next) {}
      

      当你有中间件给req添加属性时,你也可以用

      const express = require("express");
      
      /**
       * @param {express.Request & {specialParam1 : string, specialParam2 : any}} req
       * @param {express.Response} res
       * @param {express.NextFunction} next
       */
      function (req, res, next) {}
      

      或者更好的事件,为“req”上添加的每个新元素创建一个typedef,并使用“&”创建一个将它们组合在一起的类型。

      【讨论】:

      • 这具有包含express.Request 上定义的所有方法/属性的主要优点。缺点是您无法轻松记录例如每个请求正文属性都可以像其他答案中显示的虚线符号一样单独进行。我还没有想出办法来实现这两者。
      • @param {import('express').Request} req 如果没有 express 作为依赖项也可以使用
      【解决方案7】:

      [2021-03-02 更新] 原来的答案就像 100% JSDOC + 0% typescript,但我找到了 20% JSDOC + 80% typescript(纯定义)的解决方案。在typescript github 中提到了这种方法。请参阅帖子的最后一段。

      我结合其他答案并修改了一些代码,
      它可以包括在express.Request 和事件自定义请求正文中定义的所有方法/属性。
      它不仅可以在request.body中使用,还可以在req.query中使用。
      那是因为express.Request 支持泛型,所以我们可以在 JSDoc 中使用它。

      首先,记得安装@types/expressnpm install --save-dev @types/express

      其次,设置如下代码。

      // @ts-check
      /**
       * @typedef {object} showRequestBody
       * @property {string} name this is name in request body
       * @property {number} age this is age in request body
       * 
       * @typedef {object} showRequestQuery
       * @property {string} name this is name in query
       * @property {number} age this is age in query
       * 
       * @param {import('express').Request<{}, {}, showRequestBody, showRequestQuery>} req
       * @param {import('express').Response} res 
       * @param {import('express').NextFunction} next 
       */
      exports.show = function(req, res, next) {
      };
      

      注意:我在 vscode 中使用它。
      我在这里留下答案,我希望这能帮助其他人也有这个问题。


      express.Request 上定义的其他方法/属性,例如req.headers


      req.body提示


      req.query提示

      20% JSDOC + 80% 打字稿

      以下示例不需要tsconfig.json 或安装额外的tsc
      但是,你不能使用 jsdoc 来生成文档。

      带导入+导出定义

      如果你想通过导入某些模块来扩展接口,你需要在定义中使用导出。然后在 JSDOC 中导入。

      无导入+导出定义

      如果您不想在 JSDOC 中导入自定义定义,您可以只定义接口而不导入和导出。然后,您可以直接在 JSDOC 中使用它。

      扩展 express 模块

      还有另一种构建自定义界面的方法,只需使用声明模块来扩展界面即可。你甚至可以定义自定义方法。

      【讨论】:

        猜你喜欢
        • 2015-06-02
        • 2017-05-25
        • 2013-08-13
        • 2017-10-01
        • 2011-09-20
        • 1970-01-01
        • 2020-12-30
        • 1970-01-01
        • 2017-11-18
        相关资源
        最近更新 更多