在私有类方法上获取未定义的值

huangapple go评论66阅读模式
英文:

Getting undefined on private class method

问题

我有一个类的行为很奇怪。我通常不使用TypeScript,所以可能是我的用法有问题。我正在使用nodejs、TypeScript和express来开发应用程序。当我在控制器类上运行getLibs方法时,出现以下错误:

const data = this.transformRequest(req);
[1]                               ^
[1]
[1] TypeError: Cannot read properties of undefined (reading 'transformRequest')

这个类是这样的:

import { NextFunction, Request, Response } from "express";
import { Controller } from "../../common/Controller";
import { Service } from "../../common/Service";
import { AdLibService } from "./AdLibService";
import { AdLibValidator } from "./AdLibValidator";
import { ErrorHandler } from "../../errors/ErrorHandler";
import { AdLibProps } from "../../ts/types/AdLibProps";

export class AdLibController extends Controller {
  constructor() {
    super();
    this.service = new AdLibService();
    this.validator = new AdLibValidator();
  }

  private transformRequest(req: Request): AdLibProps {
    const page: number = parseInt((req.query.page as string) ?? "0");
    const pagination: number = parseInt((req.query.pagination as string) ?? "0");
    const time = req.query.timestamp;
    const data: AdLibProps = {
      timestamp: new Date(time as string),
      pagination,
      page,
    };
    return data;
  }

  public async getLibs(req: Request, res: Response, next: NextFunction) {
    const data: AdLibProps = this.transformRequest(req);
    if (!this.validator.validate(data)) {
      return next({
        status: 400,
        message: `These properties are not valid: ${this.validator.getInvalidPropertiesAsString()}`,
      });
    }
    try {
      const foundAdLibs = await this.service.getLibs(
        new Date(req.query.timestamp as string),
        data.page,
        data.pagination
      );
      return AdLibController.sendResponse(res, foundAdLibs, 200);
    } catch (e: unknown) {
      const error = ErrorHandler.ensureError(e);
      return next({
        status: 400,
        message: error.message,
      });
    }
  }

  private service: AdLibService;
  private validator: AdLibValidator;
}
import { Response } from "express";

export abstract class Controller {
  public static sendResponse(
    res: Response,
    data: any,
    status: number
  ): Response {
    return res.status(status).json(data);
  }
}
import { AdLibProps } from "../../ts/types/AdLibProps";

export class AdLibValidator {
  constructor() {
    this.invalidProperties = [];
  }

  public validate(data: AdLibProps): boolean {
    if (!this.isValidTimeStamp(data.timestamp)) {
      this.addToInvalidProperties("timestamp");
    }
    if (!this.isValidPage(data.page)) {
      this.addToInvalidProperties("page");
    }
    if (this.isValidPagination(data.pagination)) {
      this.addToInvalidProperties("pagination");
    }
    return this.getInvalidProperties.length === 0;
  }

  private isValidTimeStamp(timestamp: Date): boolean {
    const currentTime = new Date();
    if (currentTime < timestamp) {
      return false;
    }
    return true;
  }

  private isValidPage(page: number): boolean {
    return true;
  }

  private isValidPagination(pagination: number): boolean {
    return true;
  }

  public addToInvalidProperties(property: string): void {
    this.invalidProperties.push(property);
  }

  public getInvalidPropertiesAsString(): string {
    return this.invalidProperties.join(", ");
  }

  public getInvalidProperties(): string[] {
    return this.invalidProperties;
  }

  private invalidProperties: string[];
}
import express, { Router } from "express";
import { RouterErrorHandler } from "../../errors/RouterErrorHandler";
import { AdLibController } from "./AdLibController";

export class AdLibRouter {
  public static init(): Router {
    const controller = new AdLibController();
    AdLibRouter.router
      .route("/")
      .get(controller.getLibs)
      .all(RouterErrorHandler.methodNotAllowed);
    return AdLibRouter.router;
  }

  private static router: Router = express.Router();
}

我也遇到了在类中使用验证器和服务属性时的相同问题。然而,当我将这些属性和方法重构为静态方法时,它能够正常工作。我更倾向于保持它们为非静态方法,只需修复这个奇怪的行为。

英文:

I have a class that is having weird behavior. I don't usually work in TypeScript, so it might be how I'm using it. I'm using nodejs, TypeScript, and express for the application. When I run the method getLibs on the controller class I get the error:

const data = this.transformRequest(req);
[1]                               ^
[1]
[1] TypeError: Cannot read properties of undefined (reading &#39;transformRequest&#39;)

The class is:

import { NextFunction, Request, Response } from &quot;express&quot;;
import { Controller } from &quot;../../common/Controller&quot;;
import { Service } from &quot;../../common/Service&quot;;
import { AdLibService } from &quot;./AdLibService&quot;;
import { AdLibValidator } from &quot;./AdLibValidator&quot;;
import { ErrroHandler } from &quot;../../errors/ErrorHandler&quot;;
import { AdLibProps } from &quot;../../ts/types/AdLibProps&quot;;
export class AdLibController extends Controller {
constructor() {
super();
this.service = new AdLibService();
this.validator = new AdLibValidator();
}
private transformRequest(req: Request): AdLibProps {
const page: number = parseInt((req.query.page as string) ?? 0);
const pagination: number = parseInt((req.query.pagination as string) ?? 0);
const time = req.query.timestamp;
const data: AdLibProps = {
timestamp: new Date(time as string),
pagination,
page,
};
return data;
}
public async getLibs(req: Request, res: Response, next: NextFunction) {
const data: AdLibProps = this.transformRequest(req);
if (!this.validator.validate(data)) {
return next({
status: 400,
message: `These properties are not valid: ${this.validator.getInvalidPropertiesAsString()}`,
});
}
try {
const foundAdLibs = await this.service.getLibs(
new Date(req.query.timestamp as string),
data.page,
data.pagination
);
return AdLibController.sendResponse(res, foundAdLibs, 200);
} catch (e: unknown) {
const error = ErrroHandler.ensureError(e);
return next({
status: 400,
message: error.message,
});
}
}
private service: AdLibService;
private validator: AdLibValidator;
}
import { Response } from &quot;express&quot;;
export abstract class Controller {
public static sendResponse(
res: Response,
data: any,
status: number
): Response {
return res.status(status).json(data);
}
}
import { AdLibProps } from &quot;../../ts/types/AdLibProps&quot;;
export class AdLibValidator {
constructor() {
this.invalidProperties = [];
}
public validate(data: AdLibProps): boolean {
if (!this.isValidTimeStamp(data.timestamp)) {
this.addToInvalidProperties(&quot;timestamp&quot;);
}
if (!this.isValidPage(data.page)) {
this.addToInvalidProperties(&quot;page&quot;);
}
if (this.isValidPagination(data.pagination)) {
this.addToInvalidProperties(&quot;pagination&quot;);
}
return this.getInvalidProperties.length === 0;
}
private isValidTimeStamp(timestamp: Date): boolean {
const currentTime = new Date();
if (currentTime &lt; timestamp) {
return false;
}
return true;
}
private isValidPage(page: number): boolean {
return true;
}
private isValidPagination(pagination: number): boolean {
return true;
}
public addToInvalidProperties(property: string): void {
this.invalidProperties.push(property);
}
public getInvalidPropertiesAsString(): string {
return this.invalidProperties.join(&quot;, &quot;);
}
public getInvalidProperties(): string[] {
return this.invalidProperties;
}
private invalidProperties: string[];
}
import express, { Router } from &quot;express&quot;;
import { RouterErrorHandler } from &quot;../../errors/RouterErrorHandler&quot;;
import { AdLibController } from &quot;./AdLibController&quot;;
export class AdLibRouter {
public static init(): Router {
const controller = new AdLibController();
AdLibRouter.router
.route(&quot;/&quot;)
.get(controller.getLibs)
.all(RouterErrorHandler.methodNotAllowed);
return AdLibRouter.router;
}
private static router: Router = express.Router();
}

I'm also having the same issue with using the validator and service properties in the class. It works however when I refactor the properties and method to static methods. I prefer to keep them non-static and just fix this weird behavior.

答案1

得分: 1

I think when express calls the route handler, it doesn't maintain the context of the class instance, and the this keyword inside the getLibs method refers to something else (or undefined).
你可以在构造函数中显式绑定getLibs方法到类实例,如果你计划在类中的其他地方使用它,也可以绑定transformRequest方法。

英文:

I think when express calls the route handler, it doesn't maintain the context of the class instance and this keyword inside the getLibs method refers to something else (or undefined).<br>you can explicitly bind the getLibs method to the class instance in the constructor. you can also bind the transformRequest method if you plan to use it elsewhere in the class.

export class AdLibController extends Controller {
constructor() {
super();
this.service = new AdLibService();
this.validator = new AdLibValidator();
// explicitly bind the methods to the class instance
this.getLibs = this.getLibs.bind(this);
this.transformRequest = this.transformRequest.bind(this);
}
// rest of the class remains the same...
}

huangapple
  • 本文由 发表于 2023年7月18日 04:54:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/76708007.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定