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

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

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

当前回答

我通过创建一个新类型而没有全局扩展Request类型来解决这个问题。

import { Request } from 'express'
    
type CustomRequest = Request & { userId?: string }

必须使用带有可选(?)操作符的扩展属性,以避免出现“没有重载匹配此调用”错误。

软件包版本:

    "@types/express": "^4.17.13",
    "@types/morgan": "^1.9.3",
    "@types/node": "^17.0.29",
    "typescript": "^4.6.3",
    "express": "^4.18.0",

其他回答

d.从索引中的注释中可以看出。ts时,只需向全局Express名称空间声明任何新成员。例子:

declare global {
  namespace Express {
    interface Request {
      context: Context
    }
  }
}

完整的例子:

import * as express from 'express';

export class Context {
  constructor(public someContextVariable) {
  }

  log(message: string) {
    console.log(this.someContextVariable, { message });
  }
}

declare global {
  namespace Express {
    interface Request {
      context: Context
    }
  }
}

const app = express();

app.use((req, res, next) => {
  req.context = new Context(req.url);
  next();
});

app.use((req, res, next) => {
  req.context.log('about to return')
  res.send('hello world world');
});

app.listen(3000, () => console.log('Example app listening on port 3000!'))

More

扩展全局名称空间也包含在TypeScript Deep Dive中。

对于简单的情况,我在外部中间件中使用headers属性,然后在内部中间件中获得它。

// outer middleware
req.headers["custom_id"] = "abcxyz123";

// inner middleware
req.get("custom_id");

缺点:

只能存储字符串。如果您想存储其他类型,如json或number,您可能必须稍后解析它。 headers属性没有文档化。Express只记录了req.get()方法。因此,您必须使用与属性头文件一起工作的Express的确切版本。

现在回答这个问题可能已经很晚了,但无论如何,我是这样解决的:

确保在tsconfig文件中包含了类型的源代码(这可能是一个全新的线程) 在types目录中添加一个新目录,并将其命名为要为其扩展或创建类型的包。在本例中,您将创建一个名为express的目录 在express目录中创建一个文件,并将其命名为index.d.ts(必须与此完全相同) 最后,为了扩展类型,你只需要放如下代码:

declare module 'express' {
    export interface Request {
        property?: string;
    }
}

我已经改变了响应类型,包括ApiResponse(一个自定义响应对象)response <ApiResponse>

export interface ApiResponse {
    status?: string
    error?: string
    errorMsg?: string
    errorSubject?: string
    response?: any
}

const User = async (req: Request, res: Response<ApiResponse>, next: NextFunction) => {
    try {
        if (!username) return res.status(400).send({ errorMsg: 'Username is empty' })
        /* ... */
    } catch(err){
        /* ... */
    }
}

对我来说,一个简单的解决方案就是创建一个新的自定义接口来扩展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){}