如何使用JSDoc注释Express中间件?

68

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

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

在Express源代码中,我没有找到任何@typedef来帮助我。此外,我想避免使用@param {*}这样的东西。
如何使用JSDoc正确地记录Express中间件?感谢任何帮助。

1
你试过删除@return这行吗?Express路由通常不返回任何东西。 - Matt Browne
Webstorm应该会提示你错误在哪里,不是吗? - Sebas
你是如何将这个中间件添加到你的应用程序中的? - Igor Raush
在 @return {Object} 后添加一个描述,这在过去曾经为我解决了问题,或者您可以使用 eslint jsdoc 验证来告诉出现了什么问题。 - eenagy
8个回答

19

你可以使用文档记录你的中间件

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,并使用“&”将它们全部组合成一种类型。


1
这样做的主要优点是包括了在 express.Request 上定义的所有方法/属性。缺点是你不能像其他答案中显示的点表示法那样轻松地单独记录每个请求体属性。我还没有找到同时实现两者的方法。 - ZachB
5
如果没有安装 Express 作为依赖项,@param {import('express').Request} req 也可以正常工作。 - Junior Usca

17

使用DefinitelyTyped

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

更多类型

  • 在文件 /node_modules/@types/express/index.d.ts
  • 对于Response,它是e.Response,因为:

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

WebStorm

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


9
首先,我们认为中间件是函数;通常不需要特殊的类型声明。此外,中间件往往高度解耦 - 模块化 - 这意味着@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不是一个花哨的Express内部混合物;Express通过以下方式将每个中间件函数传递请求、响应和堆栈中的下一个中间件函数:

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

mw1范围内next的值为mw2


8
您不仅可以使用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){
}

这种方式记录参数成员是官方建议吗? - Leo
我刚刚把你的回答复制到了我的问题中作为答案:https://dev59.com/BLbna4cB1Zd3GeqPVRi-#57777864 - Leo

7

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

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

首先,请记得使用 npm install --save-dev @types/express 安装 @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% TypeScript

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

使用导入+导出定义

如果要借助导入某些模块扩展接口,则需要在定义中使用导出。 然后在JSDOC中导入它即可。

enter image description here

enter image description here

不使用导入和导出定义

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

enter image description here

enter image description here

扩展express模块

有另一种构建自定义接口的方法,只需使用declare module来扩展接口。您甚至可以定义自定义方法。

enter image description here

enter image description here

enter image description here


1

reqresnext 都是对象,而中间件通常不会返回,因此可以使用以下方式。

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

1
如果一个函数没有显式地返回值,它会隐式地返回 undefined。根据您遵循的样式指南,这可能会或可能不会明确地使用 @return 标签进行调用:@return {undefined}。例如,Google 的 Closure 编译器样式指南禁止使用它。https://developers.google.com/closure/compiler/docs/js-for-compiler#tags - Jeff McMahan
Object means any - RedGuy11

0

我试图在2022年学习如何实现这一目标。最终,根据目前得票最高的答案,我做了以下操作:

import { Request, Response, NextFunction } from "express";

/**
 * Some Middleware
 * @param {Request} req
 * @param {Response} res
 * @param {NextFunction} next
 * @returns
 */
export function someMiddleware(req, res, next) {
  ...
}

我正在使用VSCode,它可以检测到req、res和next对象。希望这能帮助到某些人!


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

中间件通常会返回 undefined - 许多开发人员在函数没有返回值时将返回标记视为可选或不当。 - Jeff McMahan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接