TypeScript类继承调用方法时出现TypeError的原因与解决
TypeScript继承调用基类方法时出现TypeError问题排查与解决
错误信息
TypeError: Cannot read properties of undefined (reading 'Ok')
代码片段
SettingController.ts
import { Request, Response, NextFunction } from 'express'; // ... 其他导入 export default new class SettingController extends BaseController { constructor() { super(); } async SettingOTP(req: Request, res: Response, next: NextFunction) { try { // ... 一些操作 return this.Ok(res, 'OTP setting updated successfully'); } catch (error: any) { this.BadRerquest(res, error.message); } } // ... 其他方法 }
BaseController.ts
import { Response } from 'express'; // ... 其他导入 export class BaseController { // ... 构造函数及其他方法 Ok<T>(res: Response, message: string) { return new SuccessResponse(message).send(res); } }
路由代码
import express, { Express, Router, NextFunction, Request, Response } from 'express'; import SettingController from '../../http/controller/SettingController'; // const setting_controller = new SettingController(new SettingService()); const settingRouter = express.Router(); // settingRouter.get('/get', settingController.getSetting); settingRouter.put('/opt-setting', SettingController.SettingOTP);
已尝试操作
- 确认BaseController已正确导入,Ok方法未被重写
- 在SettingController构造函数中尝试绑定方法,TypeScript编译无异常
问题核心
为何调用this.Ok会触发TypeError?如何正确使用TypeScript继承的方法?
原因分析
问题根源是方法传递时this上下文丢失:当你把SettingController.SettingOTP直接作为路由处理函数传给Express时,该方法的this不再指向SettingController实例,而是变成undefined(Express调用路由函数时不会自动绑定原实例的上下文)。即便你用new class导出单例实例,单独提取方法传递依然会丢失this绑定。
解决方法
提供三种可行方案:
方案1:构造函数内手动绑定方法到实例
修改SettingController构造函数,将方法绑定到当前实例,确保this指向正确:
export default new class SettingController extends BaseController { constructor() { super(); // 绑定方法到实例 this.SettingOTP = this.SettingOTP.bind(this); // 其他需要调用基类方法的函数也需同理绑定 } async SettingOTP(req: Request, res: Response, next: NextFunction) { try { return this.Ok(res, 'OTP setting updated successfully'); } catch (error: any) { this.BadRerquest(res, error.message); } } }
方案2:用箭头函数定义方法
箭头函数会自动捕获当前上下文的this,不会出现绑定丢失问题:
export default new class SettingController extends BaseController { constructor() { super(); } // 箭头函数定义方法,自动绑定this SettingOTP = async (req: Request, res: Response, next: NextFunction) => { try { return this.Ok(res, 'OTP setting updated successfully'); } catch (error: any) { this.BadRerquest(res, error.message); } } }
方案3:路由中用箭头函数包裹调用
注册路由时,通过箭头函数包裹方法调用,强制保留实例上下文:
settingRouter.put('/opt-setting', (req, res, next) => SettingController.SettingOTP(req, res, next));
内容的提问来源于stack exchange,提问作者Mr Coder
相关产品推荐
相关产品推荐

