打字稿错误:“请求”类型中不存在属性“用户”

时间:2017-06-06 07:03:22

标签: node.js typescript

我的快递应用程序中有以下代码

router.get('/auth/userInfo', this.validateUser,  (req, res) => {
    res.json(req.user);
});

我的IDE似乎在抱怨错误

  

错误TS2339:“请求”类型中不存在属性“用户”。

当我编译我的打字稿代码时,它似乎抛出了这个错误。任何想法为什么会这样?

11 个答案:

答案 0 :(得分:15)

我们有一个用Express和Typescript编写的大型API,这就是我们处理这种情况的方法:

我们将请求定义保存在一个文件中:

import { Request } from "express"
export interface IGetUserAuthInfoRequest extends Request {
  user: string // or any other type
}

然后在我们编写控制器功能的文件中:

import { Response } from "express"
import { IGetUserAuthInfoRequest } from "./definitionfile"

app.get('/auth/userInfo', validateUser,  (req: IGetUserAuthInfoRequest, res: Response) => {
  res.status(200).json(req.user); // Start calling status function to be compliant with Express 5.0
});

请注意,“user”不是Express的Request对象中本机可用的属性。确保您使用的是将此类属性添加到请求对象的中间件。

答案 1 :(得分:5)

req可能是来自“express”包的类型Request,用户在那里不存在。您必须使用自己的路由器处理程序扩展Request或将其强制转换为any或object。

尝试res.json(req['user'])res.json( (<any>req).user )

您也可以使用模块/全局扩充

declare module "express" { // declare module "express-serve-static-core"
  export interface Request {
    user: any
  }
}

您也可以创建自己的处理程序包装器(而不是在ExpressJs中扩展路由器功能)。

import * as express from 'express';

interface IUserRequest extends express.Request {
    user: any
}

function myHandler(handler: (req: IUserRequest, res: express.Response, next?: express.NextFunction) => any) {
    return (req: express.Request, res: express.Response, next: express.NextFunction) => {
        try {

            validateUser(req, res, (err) => { // your validateUser handler that makes a user property in express Request
                if(err)
                     throw err;

                let requestWrapper: IUserRequest = <IUserRequest>req;

                handler(requestWrapper, res, next);
            })                
        }
        catch (ex) {
            next(ex);
        }
    } 
}

let app = express();
// init stuff for express but this.validateUser handler is not needed

app.use('/testuser', myHandler((req, res) => {
    res.json(req.user);
}));

答案 2 :(得分:4)

您收到此错误,因为在本机user对象中没有express Request属性的类型定义。您应该为要向请求添加user的中间件安装类型定义。

例如,如果您使用passport库进行JWT身份验证作为中间件:

router.get('/auth/userInfo', passport.authenticate('jwt', {session:false}), (req, res, next) => {
  // Get their info from the DB and return it
  User.findOne({ email: req.user.email }, (err, user) => {
    if (err) {return next(err);}
    ...
    ...

您应该为passport添加类型定义:

npm install --save @types/passport

答案 3 :(得分:3)

您需要进行声明合并:

“声明合并意味着编译器将两个单独的合并 以相同名称声明的声明将成为一个定义。”

为此,您可以在项目src文件夹(或所需位置)中创建一个名为type.d.ts的文件,其内容如下:

declare namespace Express {
  export interface Request {
      user: any;
  }
  export interface Response {
      user: any;
  }
}

在这里,我们告诉编译器将用户属性添加到我们的“请求和响应”定义中。

下一步,我们需要将此附加到tsconfig.json。

示例:

{
  "compilerOptions": {
      "module": "commonjs",
      "moduleResolution": "node",
      "pretty": true,
      "sourceMap": true,
      "target": "es6",
      "outDir": "./dist",
      "baseUrl": "./lib"
  },
  "include": [
      "lib/**/*.ts"
  ],
  "exclude": [
      "node_modules"
  ],
  "files":["types.d.ts"]
}

现在,打字稿编译器知道Request拥有一个名为user的属性,在我的情况下可以接受任何json对象。您可以根据需要限制字符串的类型。

The final result is that, no error in VSCode =)

答案 4 :(得分:2)

对于使用GraphQL的人来说,graphqlExpress函数存在一个问题,即不接受您的新interface。我一直尝试遵循this guide,直到遇到这个确切的问题。我已经找到了解决方案:

this.app.use("/graphql", bodyParser.json(), this.auth, graphqlExpress((req: AuthRequest | undefined) => ({ 
    schema,
    context: {
        user: req!.user
    }
})));

AuthRequest界面中:

import {Request} from "express"

export interface AuthRequest extends Request {
    user?: string
}

Typescript将不允许您使用AuthRequest,除非也允许对其进行未定义。因此,| undefined。 (source

在这一点之后,用户对象在请求对象上不存在100%,因此?在用户之后。

答案 5 :(得分:1)

为此https://developer.okta.com/blog/2018/10/30/basic-crud-angular-and-node我在okta-angular-node中使用了

我为req.user遇到了类似的错误。请检查上面给定链接中的服务器/身份验证。

类型转换对我有用。尝试进行如下投射

req.user(req['user'])

答案 6 :(得分:1)

如果您使用的是 ts-node 而不是 ts-node-dev,请执行以下操作:

  1. 在您的 typings 文件夹中创建一个 src 文件夹。
  2. typings 文件夹中创建一个文件夹,名称为您要扩展的 package
  3. 使用新文件夹创建一个 index.d.ts 文件。

就我而言,我扩展了 express,结果是这样的:

  src/
    - typings/
      - express/
        - index.d.ts

index.d.ts 文件中我有这个:

declare module Express {
    export interface Request {
        bucketUrl: string;
        fileName: string;
    }
}

记得更新您的.tsconfig

{
  "compilerOptions": {
    "typeRoots" : ["./node_modules/@types", "./typings"]
  }
}

答案 7 :(得分:0)

typeRoots 添加到您的 tsconfig.json,这将告诉打字稿在哪里寻找 declaration files。默认情况下,打字稿在 /node_modules/@types 中查找,但是当您指定此属性时,这些默认值将被清除。您可以阅读更多here

tsconfig.json

{
  "compilerOptions": {
    "typeRoots": ["./node_modules/@types", "./src/util"]
  }
}            

types.d.ts

import { User } from '../models/user'

declare global {
  namespace Express {
    interface Request {
      user: User
    }
  }
}

文件夹结构

node_modules
tsconfig.json
/src/
   /models/
      user.ts
   /util/
      types.d.ts

答案 8 :(得分:0)

您需要使用下面提到的 fastify 装饰器来装饰请求,

fastify.decorateRequest('user', <pass null or empty string here>)

并处理用户对象中应该包含的内容。

官方文件 - https://www.fastify.io/docs/latest/Decorators/

答案 9 :(得分:0)

您可以尝试在 middleware.ts 文件中包含以下代码段:

declare module 'express-serve-static-core' {
  interface Request {
    user?: string
  } 
}

答案 10 :(得分:-1)

一个老问题,但是如果有人像我一样偶然发现这个问题,请看一下“声明合并”,为我解决了这个问题。

https://www.typescriptlang.org/docs/handbook/declaration-merging.html

https://truetocode.com/extend-express-request-and-response-typescript-declaration-merging/