英文:
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 'transformRequest')
The class is:
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 { ErrroHandler } 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 = ErrroHandler.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'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...
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论