TypeScript中this.method与super.method差异及跨项目调用异常解析
问题:TypeScript继承中this调用父类方法在不同项目中表现差异的原因
类继承结构
export class BaseClass { public getDevice() { } } export class InheritClass extends BaseClass { constructor() { super(); } public devices() { // this.getDevice() // 在Next.js项目中可用,但在Express项目中为undefined // super.getDevice() // 在两个项目中均可用 } }
现象说明:子类InheritClass的devices方法中,通过this.getDevice()调用父类方法时,在Next.js项目中正常,但在Express项目里this.getDevice为undefined;而用super.getDevice()在两个项目中都能正常执行。
两个项目的tsconfig.json配置
Express项目
"target": "ES2018", "module": "commonjs", "lib": ["es6", "dom"],
Next.js项目
"target": "esnext", "lib": [ "dom", "dom.iterable", "esnext" ], "module": "esnext",
Express项目中的额外相关代码(中间件类)
import { injectable } from 'inversify'; import "reflect-metadata"; import { Request, Response, NextFunction } from "express"; import rateLimit from 'express-rate-limit'; import { ResponseData } from "@/interface/responseData"; import { generalMsg } from "@/msg"; @injectable() export class BaseMiddleware { private limiter = rateLimit({ windowMs: 1 * 60 * 1000, // 限制1分钟 max: 1000, // 1分钟内最多1000次请求 }); public async execute(req: Request, res: Response, next: NextFunction): Promise<void | {}> { try { this.limiter(req, res, () => { next(); }); } catch (error) { console.error(error); } } protected badRequest(error: {details: any}, res: Response){ const responseData = new ResponseData( null, generalMsg.error.request, false, error.details ); return res.status(400).json(responseData.toJson()); } } import "reflect-metadata"; import { injectable } from "inversify"; import { Request, Response, NextFunction } from "express"; import Joi from "joi"; import { BaseMiddleware } from "@middleware/base.middleware"; @injectable() export class DeviceMiddleware extends BaseMiddleware { constructor() { super(); } public async addDevice( req: Request, res: Response, next: NextFunction ): Promise<void | {}> { try { const schema = Joi.object({ userId: Joi.number().allow(null), deviceToken: Joi.string().required(), }); const validateSchema = await schema.validateAsync(req.body); next(); } catch (error: any) { if (error) { return super.badRequest(error, res); } } } }
原因分析
模块编译与输出差异
- Next.js采用ESNext模块系统,TypeScript编译后保留原生ES6+类的继承逻辑,子类实例的
this能正确指向自身,自然可以通过原型链访问到父类的getDevice方法。 - Express采用CommonJS模块系统,TypeScript将ES类编译为CommonJS风格的构造函数实现,这种编译方式下类的原型链绑定逻辑与原生ES类存在差异,容易为
this指向异常埋下隐患。
- Next.js采用ESNext模块系统,TypeScript编译后保留原生ES6+类的继承逻辑,子类实例的
Inversify装饰器的影响
Express项目中的类都使用了@injectable()装饰器,Inversify在处理这些类时,会修改类的构造逻辑或创建实例代理,打乱了子类实例的this上下文。此时this.getDevice()中的this并非指向子类实例,因此无法找到父类方法;而super.getDevice()是直接调用父类原型上的方法,绕过了this指向的问题,因此在两个项目中都能正常工作。方法访问方式的本质区别
this.getDevice()依赖于this的指向,只有当this正确指向子类实例时,才能通过原型链找到父类的方法。super.getDevice()是直接引用父类原型的方法,不依赖当前this的上下文,因此不受环境差异影响。
内容的提问来源于stack exchange,提问作者Hai Tien
相关产品推荐
相关产品推荐

