无法在TypeScript

时间:2019-01-03 21:58:58

标签: node.js typescript express

这个问题已经问了好几次了,但是给出的答案对我都没有用。我正在尝试扩展Express Request对象以包括存储User对象的属性。我创建了一个声明文件express.d.ts,并将其与我的tsconfig.json放在同一目录中:

import { User } from "./src/models/user";

declare namespace Express {
    export interface Request {
        user: User;
    }
}

然后我尝试在secured-api.ts中对其进行分配:

import express from 'express';
import { userService } from '../services/user';

router.use(async (req, res, next) => {
    try {
        const user = await userService.findByUsername(payload.username);

        // do stuff to user...

        req.user = user;
        next();
    } catch(err) {
        // handle error
    }
});

我收到以下错误:

src/routes/secured-api.ts:38:21 - error TS2339: Property 'user' does not exist on type 'Request'.

38                 req.user = user;
                       ~~~~

我的User类是:

import { Model, RelationMappings } from 'objection';

export class User extends Model {

    public static tableName = 'User';
    public static idColumn = 'username';

    public static jsonSchema = {
        type: 'object',
        required: ['fname', 'lname', 'username', 'email', 'password'],

        properties: {
            fname: { type: 'string', minLength: 1, maxLength: 30 },
            lname: { type: 'string', minLength: 1, maxLength: 30 },
            username: { type: 'string', minLength: 1, maxLength: 20 },
            email: { type: 'string', minLength: 1, maxLength: 320 },
            password: { type: 'string', minLength: 1, maxLength: 128 },
        }
    };

    public static modelPaths = [__dirname];

    public static relationMappings: RelationMappings = {

    };

    public fname!: string;
    public lname!: string;
    public username!: string;
    public email!: string;
    public password!: string;
}

我的tsconfig.json是:

{
    "compilerOptions": {
      "target": "es6",                          /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */
      "module": "commonjs",                     /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
      "lib": ["es2015"],                             /* Specify library files to be included in the compilation. */
      "outDir": "./build",                      /* Redirect output structure to the directory. */
      "strict": true,                           /* Enable all strict type-checking options. */
      "esModuleInterop": true                   /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
    }
}

我的目录结构是:

backend/
    package.json
    tsconfig.json
    express.d.ts
    src/
        models/
            user.ts
        routes/
            secured-api.ts

我在这里做什么错了?

5 个答案:

答案 0 :(得分:1)

问题是您没有扩充Express定义的express全局命名空间,而是在模块中创建了一个新的命名空间(一旦使用import,该文件就会成为一个模块)。

解决方案是在global

中声明名称空间
import { User } from "./src/models/user";

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

或者不使用模块导入语法,只需引用类型:

declare namespace Express {
    export interface Request {
        user: import("./src/models/user").User;
    }
}

答案 1 :(得分:1)

我遇到了同样的问题...

您不能只使用扩展请求吗? 喜欢:

interface RequestWithUser extends Request {
    user?: User;
}
router.post('something',(req: RequestWithUser, res: Response, next)=>{
   const user = req.user;
   ...
}

另一方面,如果您使用带有express的异步回调,请确保使用用户express-async包装器,或者确保您确切地知道自己在做什么。我建议:awaitjs

答案 2 :(得分:0)

对我来说,我只是在偷懒。

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

router.use(async (req, res, next) => {
   const user = req.user as User;
   // ...
});

答案 3 :(得分:0)

我尝试了很多解决方案,但是没有一个起作用。

但是它也可以如此简单并且完美地工作。 当然,您可以将AuthenticatedRequest保存在其他任何地方。

import { IUser } from './src/_models/user.model';

export interface AuthenticatedRequest extends Request {
  user: IUser;
}
static async getTicket(req: AuthenticatedRequest, res: Response){}

更新:

所以我从这里发现了一些有趣的东西: Import class in definition file (*d.ts)

声明命名空间Express应该是打字稿的第一行,将其视为全局

declare namespace Express {

  interface Request {
    user: import('./src/modules/models/user.model').IUser;
    uploadedImage: { key: string; type: string };
    group: import('./src/modules/models/group.model').IGroup;
  }
}

答案 4 :(得分:-1)

0

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

请参见下面的示例,其中接口声明以打字稿合并

interface Boy {
height: number;
weight: number;
}

interface Boy {
mark: number;
}

let boy: Boy = {height: 6 , weight: 50, mark: 50}; 

extend request response