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

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

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

当前回答

这就是我在使用Nestjs和Express时的工作方式。截至2020年11月。

创建一个文件:./@types/express- server -static-core/index.d.ts

注意:必须有上面的路径和文件名。这样Typescript声明合并就可以了。

import { UserModel } from "../../src/user/user.model";

declare global{
    namespace Express {
        interface Request {
            currentUser: UserModel
        }
    }
}

将其添加到tsconfig.json中

"typeRoots": [
      "@types",
      "./node_modules/@types",
    ]        

其他回答

我用了回应。当地人反对储存新财产。下面是完整的代码

export function testmiddleware(req: Request, res: Response, next: NextFunction) {
    res.locals.user = 1;
    next();
}

// Simple Get
router.get('/', testmiddleware, async (req: Request, res: Response) => {
    console.log(res.locals.user);
    res.status(200).send({ message: `Success! ${res.locals.user}` });
});

为了帮助那些只是在这里寻找其他尝试的人,这是我在2020年5月底试图扩展ExpressJS的Request时所做的工作。我不得不尝试了十几件事,才让这个工作:

在tsconfig的“typeRoots”中翻转每个人推荐的顺序。如果你在tsconfig中有一个rootDir设置,比如"./src",不要忘记删除src路径。例子:

"typeRoots": [
      "./node_modules/@types",
      "./your-custom-types-dir"
]

自定义扩展('./your-custom-types-dir/express/index.d.ts")的例子。在我的经验中,我不得不使用内联导入和默认导出来使用类作为类型,所以这也显示出来了:

declare global {
  namespace Express {
    interface Request {
      customBasicProperty: string,
      customClassProperty: import("../path/to/CustomClass").default;
    }
  }
}

更新你的nodemon。Json文件,将“——files”命令添加到ts-node,示例:

{
  "restartable": "rs",
  "ignore": [".git", "node_modules/**/node_modules"],
  "verbose": true,
  "exec": "ts-node --files",
  "watch": ["src/"],
  "env": {
    "NODE_ENV": "development"
  },
  "ext": "js,json,ts"
}

虽然这是一个非常古老的问题,但我最近偶然发现了这个问题。接受的答案工作得很好,但我需要添加一个自定义接口请求-一个接口,我一直在我的代码中使用,并不能很好地与接受的答案。从逻辑上讲,我尝试了这样做:

import ITenant from "../interfaces/ITenant";

declare namespace Express {
    export interface Request {
        tenant?: ITenant;
    }
}

但这不起作用,因为Typescript处理。d。Ts文件作为全局导入,当它们中有导入时,它们被视为普通模块。这就是为什么上面的代码不能在标准的typescript设置下工作。

这是我最后做的事情

// typings/common.d.ts

declare namespace Express {
    export interface Request {
        tenant?: import("../interfaces/ITenant").default;
    }
}
// interfaces/ITenant.ts

export interface ITenant {
    ...
}

我通过创建一个新类型而没有全局扩展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的中间件系统不适合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。