繁体   English   中英

Typescript 错误:属性“用户”在类型“请求”上不存在

[英]Typescript Error: Property 'user' does not exist on type 'Request'

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

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

我的 IDE 似乎在抱怨错误

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

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

我们有一个用 Express 和 Typescript 编写的大型 API,这就是我们处理此类场景的方式:

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

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

然后在我们编写 controller 函数的文件中:

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
});

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

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

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

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

import { Request } from "express"

declare module "express" { 
  export interface Request {
    user: any
  }
}

较新的 express 定义可能需要增加核心 def

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);
}));

更新:由于 Typescript 正在发展,我也会考虑使用Type Guards

if (hasUser(req)) {
    console.log(req.user)
}

function hasUser(request: Request): request is Request & { user: number } {
    return 'user' in request && typeof request['user'] == 'number'
}

您需要进行声明合并:

“声明合并意味着编译器将两个使用相同名称声明的单独声明合并到一个定义中。”

为此,您可以在项目 src 文件夹(或任何您想要的位置)中创建一个名为 types.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"]
}

现在,typescript 编译器知道 Request,它有一个名为 user 的属性,在我的例子中,它可以接受任何 json object。 如果需要,您可以限制字符串的类型。

最终结果是,VSCode 没有错误 =)

您收到此错误是因为本机express Request object 中的user属性没有类型定义。 您应该为用于将user添加到请求的中间件安装类型定义。

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

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
  1. 在“src”文件夹中创建名为types的新文件夹
  2. types文件夹中创建文件<filename>.d.ts
  3. 添加以下代码:
declare namespace Express {
  export interface Request {
    user: any
  }
}
  • 你会注意到错误消失了
  1. typeRoots部分内,将以下内容添加到tsconfig.json文件中:
"typeRoots": [
      "./node_module/@types",
      "./src/types"
],
  • 您可以像这样使用 express 类型的Request
import { Request, Response } from "express";
router.get('/auth/userInfo', this.validateUser,  (req: Request, res: Response) => {
    res.json(req.user);
});
  • 如果您使用 ts-node ,当您尝试执行您的.ts文件时,您将收到相同的错误,因为 ts-node 忽略.d.ts文件,除非您将标志--files添加到package.json脚本,如下所示:
"scripts": {
    .
    .
    "dev": "ts-node --files src/app.ts"
  }
  • 有关此主题的更多信息,您可以查看 Microsoft 团队创建的这个存储库

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

  1. 在您的src文件夹中创建一个typings文件夹。
  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"]
  }
}

对于使用 GraphQL 的人来说, graphqlExpress function 不接受您的新interface存在问题。 我一直在尝试遵循本指南,直到遇到这个确切的问题。 我想出了这个解决方案:

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 | undefined 来源

在此之后,用户 object 不会 100% 存在于请求 object 上,因此? 在用户之后。

就我而言,使用? 解决问题。

import { Request } from "express";

interface MyUserRequest extends Request {
  // Use `user?:` here instead of `user:`.
  user?: string;
}

router.get('/auth/userInfo', (req: MyUserRequest, res) => {
  res.status(200).json(req.user)
});

只需扩展“请求”而不进行声明。

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

我为req.user想出了类似的错误。 请检查上面给出的链接中的 server/auth.ts。

类型转换对我有用。 尝试按如下方式投射

req.user(req['user'])

typeRoots添加到您的tsconfig.json中,这将告诉 typescript 在哪里查找声明文件 默认情况下 typescript 在/node_modules/@types中查找,但是当您指定此属性时,这些默认值将被清除。 你可以在这里阅读更多。

tsconfig.json

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

类型.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

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

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

declare global {
  namespace Express {
    interface Request {
      user?: any
    }
  }
}

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

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

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

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

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

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

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

我最近遇到了同样的问题,我按照之前评论和这个 repo 中的解决方案,我仍然遇到同样的问题。 在进行更多挖掘之后,它似乎是 ts-node 的一个错误。

要解决这个问题,您需要使用 --files 标志运行您的服务器

因此,如果您通常运行服务器 ts-node ./src/server.ts 或 nodemon ./src/server.ts 将其更改为 ts-node --files ./src/server.ts 或 nodemon --files ./src /server.ts

之后,我能够在启动服务器时摆脱 VScode 错误和错误。

因为“用户”属性在本机快递“请求”object 中不存在。

此问题有多种解决方法。

1-最简单的一个-...

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

2-将以下代码添加到app.js或接口文件一次。

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

就我而言,我必须这样做

interface RequestUserAuth extends Request {
user?: {
    id: string
    role: string
    // or any type you want but you must to use it like that "user?: etc..."
   }
}

    app.get('/', auth, (req: RequestUserAuth, res: Response) => {
    console.log(req.user)  
   })

做就是了

import { Request, Response} from "express";

然后这样做;

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

我有一个工作 index.d.ts 使用这里的其他提示,但事实上它与不相关的 index.ts 在同一个文件夹中导致它无法工作。 我将 index.d.ts 移动到它自己的类型文件夹中,这些类型开始被使用。 我猜与 index.ts 处于同一级别发生了冲突。

只是分享我的 types/index.d.ts 以防它帮助那些也在使用 Prisma 的人

import { User as PrismaUser } from "../prisma/prismaclient";

declare module "passport" {
  namespace Express {
    interface User extends PrismaUser {}
  }
}

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


declare module "express-session" {
  interface SessionData {
    user: PrismaUser;
  }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM