【问题标题】:Cannot read property of constructed class无法读取构造类的属性
【发布时间】:2021-04-23 16:29:10
【问题描述】:

我对 TypeScript 还很陌生,最近遇到了一个我无法解决的问题。

我正在使用 Express 创建一个 REST API。我有一个路由器,它调用一个控制器,在控制器内部,我调用一个服务的方法,然后返回响应。

这是我的路由器的外观:

import express from 'express';

import { BidsController } from '../../controllers/bids.controller';

const router = express.Router();
const bidsController = new BidsController();

router.post('/bids', isAuthenticated, checkRoles(['user']), checkIsVerified, bidsController.createBid);

路由器有一些中间件,但它们都没有使用bidsController,所以我相信它们不会导致错误。

这是我的bidsController:

import validator from '../validator';
import { BidsService } from '../services/bids.service';

class BidsController implements IBidsController {
  bidsService;

  constructor() {
    this.bidsService = new BidsService();
  }

  async createBid(req: Request, res: Response, next: NextFunction): Promise<void> {
    const { params, body } = req;

    try {
      validator.bids.create(params, body);

      const { userId } = res.locals.tokenInfo;
      const { value } = body;

      const response = await this.bidsService.createBid(value, userId);
      res.status(201).json(response);
    } catch (exception) {
      next(exception);
    }
  }
}

这是服务:

class BidsService implements IBidsService {
  public async createBid(value: number, userId: string): Promise<IBid> {
    const bid = new Bid({
      value,
      user: userId,
    })

    await bid.save();

    return bid;
  }
}

所以,当我使用 Postman 调用 POST /bids 端点时,我得到了错误:

"TypeError: Cannot read property 'bidsService' of undefined"

你能帮我解决这个问题吗?

【问题讨论】:

  • 当传递给你的 router.post() 函数时,bidsController.createBid 没有正确绑定到 bidsController 实例——你实际上只是传递了一个函数的引用。您需要在调用时指定函数内部的 this 应该是什么。将其替换为 bidsController.createBid.bind(bidsController)。
  • 这似乎解决了这个问题。有什么办法可以避免使用绑定?
  • @GvidasPranauskas 是:(...args) =&gt; bidsController.createBid(...args)

标签: javascript node.js typescript express


【解决方案1】:
router.post('/bids', isAuthenticated, checkRoles(['user']), 
checkIsVerified, bidsController.createBid.bind(bidsController)); // <- THE FIX

首先,这是一个 JS 运行时错误,与 TS 无关。

this 关键字是在调用对象的“方法”时动态确定的。

通常你直接调用那个对象的方法,比如bidsController.createBid()。这会将createBid 中的this 关键字绑定到bidsController

但是,在您的情况下,您不会直接调用它。相反,您只需将 bidsController.createBid 的值(一个函数)作为回调传递给 router.post,稍后将调用该回调。

this 关键字在这种情况下是未绑定的,因为稍后调用它时,它没有任何关于 bidsController 的信息。为了提供该信息,您使用 bidsController.createBid.bind(bidsController) 预先绑定它。

另外一种提前绑定的方式,就是在声明类方法的时候使用箭头函数。

class BidsController implements IBidsController {

  createBid = async (req: Request, res: Response, next: NextFunction) => {
    const { params, body } = req;

【讨论】:

  • 好的,但是有没有办法以其他方式应用bind?将其应用于每个路由器语句似乎有太多重复的代码。
  • 是的,刚看到。这解决了问题。但是为什么箭头函数会这样呢?
  • 箭头函数的引入主要是为了解决this绑定问题。这就是它的作用。
  • 现在你知道魔鬼了。我建议你花更多的时间来充分了解this关键字的事情,否则,期待未来的footgun。这是一个令人讨厌的概念,你需要努力学习。
猜你喜欢
  • 1970-01-01
  • 2021-11-28
  • 2018-06-15
  • 1970-01-01
  • 1970-01-01
  • 2021-05-15
  • 1970-01-01
  • 2021-11-20
  • 2023-01-31
相关资源
最近更新 更多