我试图添加一个属性来表达使用typescript从中间件请求对象。但是,我不知道如何向对象添加额外的属性。如果可能的话,我宁愿不用括号。

我正在寻找一个解决方案,允许我写类似的东西(如果可能的话):

app.use((req, res, next) => {
    req.property = setProperty(); 
    next();
});

当前回答

对我来说,一个简单的解决方案就是创建一个新的自定义接口来扩展express Request。 这个接口应该包含所有可选的自定义req属性。 将此接口设置为中间件请求的类型。

// ICustomRequset.ts
   import { Request } from "express"
   export default interface ICustomRequset extends Request {
       email?: string;
       roles?: Array<string>;
   }

// AuthMiddleware.ts
...
export default async function (
  req: ICustomRequset,
  res: Response,
  next: NextFunction
) {
  try {
      // jwt code
      req.email=jwt.email
      req.roles=jwt.roles
      next()
  }catch(err){}

其他回答

在mac节点12.19.0和express 4上,使用护照进行身份验证,我需要扩展我的Session对象

与上面相似,但略有不同:

import { Request } from "express";


declare global {
  namespace Express {
    export interface Session {
      passport: any;
      participantIds: any;
      uniqueId: string;
    }
    export interface Request {
      session: Session;
    }
  }
}

export interface Context {
  req: Request;
  user?: any;
}```

.d。Ts声明是黑客。简单地接受这样一个事实:express的中间件系统不适合typescript。所以不要用它。

错误代码示例:

const auth = (req) => {
  const user = // parse user from the header

  if(!user)
     return res.status(401).send({ result: 'unauthorized-error' })

  req.user = user
  return next()
}

app.get('/something', auth, (req, res) => {
  // do something
})

更好的代码:

const auth = (req) => {
  return // parse user from the header
}

app.get('/something', (req, res) => {
  const user = auth(req)
  if(!user)
    return res.status(401).send({ result: 'unauthorized-error' })
  // do something
})

你可以使用更高阶的函数来恢复中间件的使用:

Const auth = (req) => { 从头文件返回// parse user } const withUser =(回调:(foo, req, res) => void) => (req, res) => { Const user = auth(req) 如果用户(!) 返回res.status(401)。发送({result: 'unauthorized-error'}) 返回回调(user, req, res) } app.get('/something', withUser((user, req, res) => { //做某事 }))

如果你愿意,你甚至可以把它们堆叠起来:

const withFoo = (callback) => (req, res) => { /* ... */ } const withBar = (callback) => (req, res) => { /* ... */ } const withBaz = (callback) => (req, res) => { /* ... */ } const withFooBarAndBaz = (callback) => (req,res) => { withFoo((foo) => withBar((bar) => withBaz((baz) => callback({ foo, bar, baz }, req, res) )(req,res) )(req,res) )(req,res) } app.get('/something', withFooBarAndBaz(({ foo, bar, baz }, req, res) => { // do something with foo, bar and baz }))

只要使用语言,而不是表达促进的不安全突变。

编辑:我使用第一个建议的解决方案。但不同的是,我的auth函数抛出了一个错误,我可以捕捉并返回正确的响应,所以我不需要在控制器中这样做。例如:

app.get('/something', withResponse((req) => {
   const user = auth(req)
   return success({
     message: `Hi ${user.name}`
   })
}))

我还发送返回类型,而不是手动调用res.send。它还允许我输入响应。我建议你也去查查tRPC。

在2021年,这个方法是有效的:

在express 4.17.1中,https://stackoverflow.com/a/55718334/9321986和https://stackoverflow.com/a/58788706/9321986的组合工作:

在类型/快递/ index.d.ts:

declare module 'express-serve-static-core' {
    interface Request {
        task?: Task
    }
}

在tsconfig.json中:

{
    "compilerOptions": {
        "typeRoots": ["./types"]
    }
}

可选择的解决方案

这实际上并没有直接回答这个问题,但我提供了一个替代方案。我也在与同样的问题作斗争,并尝试了该页面上几乎所有的界面扩展解决方案,但没有一个有效。

这让我停下来思考:“为什么我实际上在修改请求对象?”

使用response.locals

Express开发人员似乎认为用户可能希望添加自己的属性。这就是为什么有一个locals对象。问题是,它不在请求中,而是在响应对象中。

响应。Locals对象可以包含您可能希望拥有的任何自定义属性,这些属性封装在请求-响应周期中,因此不会暴露给来自不同用户的其他请求。

需要存储userId?只需设置response.locals.userId = '123'。没有必要纠结于打字。

它的缺点是,您必须传递响应对象,但很可能您已经这样做了。

https://expressjs.com/en/api.html#res.locals

打字

另一个缺点是缺乏类型安全性。然而,你可以在Response对象上使用泛型类型来定义body和locals对象的结构:

响应< MyResponseBody, MyResponseLocals >

https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/express/index.d.ts#L127

警告

你不能保证userId属性确实在那里。您可能希望在访问它之前进行检查,特别是在对象的情况下。

使用上面的例子来添加一个userId,我们可以有这样的东西:

interface MyResponseLocals {
  userId: string;
}

const userMiddleware = (
  request: Request,
  response: Response<MyResponseBody, MyResponseLocals>,
  next: NextFunction
) => {
  const userId: string = getUserId(request.cookies.myAuthTokenCookie);
  // Will nag if you try to assign something else than a string here
  response.locals.userId = userId;
  next();
};

router.get(
  '/path/to/somewhere',
  userMiddleware,
  (request: Request, response: Response<MyResponseBody, MyResponseLocals>) => {
    // userId will have string type instead of any
    const { userId } = response.locals;

    // You might want to check that it's actually there
    if (!userId) {
      throw Error('No userId!');
    }
    // Do more stuff
  }
);

他们提供的解决方案没有一个对我有效。我最终只是扩展了Request接口:

import {Request} from 'express';

export interface RequestCustom extends Request
{
    property: string;
}

然后使用它:

import {NextFunction, Response} from 'express';
import {RequestCustom} from 'RequestCustom';

someMiddleware(req: RequestCustom, res: Response, next: NextFunction): void
{
    req.property = '';
}

编辑:根据你的tsconfig,你可能需要这样做:

someMiddleware(expressRequest: Request, res: Response, next: NextFunction): void
{
    const req = expressRequest as RequestCustom;
    req.property = '';
}