express:项目本地中间件扩展 Express.Request
Posted
技术标签:
【中文标题】express:项目本地中间件扩展 Express.Request【英文标题】:express: project-local middleware extending Express.Request 【发布时间】:2016-04-07 06:38:57 【问题描述】:我正在开发基于express 并使用 TypeScript 1.7 编写的节点服务器。我正在使用一些特定于项目的中间件,它们扩展了现有的快速请求或响应接口,但我还不能让它完全工作(没有 tsc 抱怨在 req
或 res
中找不到 X)。我找到了其他 questions 关于这个问题,但它们要么已经过时(我猜),要么解决方案不是直截了当的。
我查看了existing middleware 的定义,但如果不手动编写单独的 d.ts 文件并在 typings/tsd.d.ts 中引用它们,我就无法让它工作。这是我的设置:
// middleware/foobar.ts
declare module Express
export interface Request
foobar?: string;
/* my project-related middleware extends the request by `foobar` */
export = function(req: Express.Request, res, next)
req.foobar = 'FooBar';
next();
;
// main.ts
import express = require('express');
var app = express();
app.use(require('./middleware/foobar'));
app.get('/foobar', (req, res) =>
/* tsc: Property 'foobar' does not exist on type 'Request' */
res.send(req.foobar);
);
扩展 express 的请求和响应接口的最佳做法是什么?如果可能,无需编写单独的 d.ts、在类型目录中操作任何内容或使用 /// <reference path="..." />
cmets。
【问题讨论】:
您可以让 tsc 使用定义标志为您的代码生成 d.ts 文件。你所要做的就是你的代码应该实现/扩展请求/响应接口/类 @toskv 如果我将 tsconfig.json 中的declaration
设置为 true,tsc 会抱怨 exports = function
语句,因为它是“使用私有名称 'Express.Request'”,即使我在此处将 <reference>
添加到 express.d.ts 文件中。编译后(使用tsc
或tsc -w
观察变化),有main.d.ts,但由于上述原因,middleware.d.ts 丢失了。并且 main.ts 仍在抱怨缺少 req.foobar ...
这听起来更像你不应该能够扩展 express.request 因为它被定义为私有。 :(
但是现有快速中间件的类型(以express-session 为例)可以正常工作。我使用tsc install express-session --save
调查了它是如何工作的。它添加了对 typings/tsd.d.ts 的引用,但是一旦我删除了该引用,它就再也找不到 req.session
了。而且我不想自己修改 tsd.d.ts,因为下一个 tsd 命令可能会删除我的硬编码引用。
你不应该有,难道你没有 tsconfig.json 和 package.json 文件来管理依赖关系吗?
【参考方案1】:
我自己找到了一个解决方案,使用this example 作为参考。我的中间件需要包装在一个声明的模块中,所以 middleware/foobar.ts 看起来像这样:
declare module Express
export interface Request
foobar?: string;
declare module 'foobar'
function foobar(req: Express.Request, res, next)
req.foobar = 'FooBar';
next();
export = foobar;
如果您在中间件中使用类或其他导入的东西,那就更麻烦了。在我的示例中,我的中间件使用我自己的“EntityManager”类,它是数据库连接的抽象(对我来说是 mysql)。我的中间件(对我来说是 middleware/database.ts
)现在看起来像这样:
declare module Express
import Manager as EntityManager from 'entity-manager';
export interface Request
entityManager?: EntityManager;
declare module 'database'
import * as mysql from 'mysql';
import Manager as EntityManager from 'entity-manager';
/* some middleware-related code */
var pool = mysql.createPool(...);
var entityManager = new EntityManager(pool);
/* *** */
/* the actual exported function */
function database(req: Express.Request, res, next)
req.entityManager = entityManager;
next();
;
export = database;
请注意,我的 EntityManager 类被导入两次,每个模块声明一次。仅在两个模块上方导入它似乎不起作用。
更新
在声明的模块中包含实际代码(在我的例子中为'database'
)在 JS 文件中不会产生任何输出。
在常规模块中包含该代码要求名称不包含撇号(例如,其中不允许使用连字符)并且也不会产生单功能导出代码。
使实际代码完全脱离模块(因此只有声明的 Express 模块和扩展请求)会生成正确的 JS,但我的文本编辑器在 req 中找不到 entityManager
。
似乎我需要将类型(例如我自己对 Express.Request 的扩展)放入一个专用的 d.ts 文件中,其中不存在实际代码。
【讨论】:
找到合适的解决方案了吗? 至少我不太明白你在“更新”中写的东西..以上是关于express:项目本地中间件扩展 Express.Request的主要内容,如果未能解决你的问题,请参考以下文章