簡體   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