首页 > 解决方案 > 在构造函数中设置的函数中使用 this 的属性时,编译的 JavaScript 代码给出未定义

问题描述

我正在开发一个原型,目标是用 TypeScript 中的 express 框架编写一个 web 服务,将其编译为 TS 并将其托管在 firebase 函数环境中。服务中的代码层是控制器层,目前也是业务规则的业务逻辑层。可能与 .Net 编写的 web 服务中看到的层几乎相同。通过使用 inversifyJS 框架的依赖注入,我将逻辑类注入到控制器中。

到目前为止的部分 TypeScript 代码:

@injectable()
export class Service1Controller extends ApiController implements IService1Controller {
    public constructor(
        @inject(TYPES.IService1Logic)
        private service1Logic: IService1Logic
    ) { super() }

    private fastGet(request: Request, response: Response) {
        const original = request.query.text;
        const changed = this.service1Logic.UpdateFastGet(original);
        response.status(200).send(changed);    
    }
}


export interface IService1Logic {
    UpdateFastGet(text: string): string;
}

@injectable()
export class Service1Logic implements IService1Logic {

    UpdateFastGet(text: string): string {
        console.log(`[Service1Logic/UpdateFastGet]: ${text}`);
        text = `${text} -> service1[fastget]`;
        return text;
    }
}

这是(部分)控制器代码的编译输出

constructor(service1Logic) {
    super();
    this.service1Logic = service1Logic;
}
fastGet(request, response) {
    const original = request.query.text;
    const changed = this.service1Logic.UpdateFastGet(original);
    response.status(200).send(changed);
}

使用 firebase 函数模拟器在本地测试代码时,我收到一个错误,即无法从 undefined 读取属性 service1Logic。所以这似乎是未定义的,我不知道为什么。

我还尝试隔离错误并使用下一个代码重现它:

@injectable()
export class Class1 extends baseClass implements Interface1 {

    constructor(
        @inject(TYPES.Interface2)
        private class2: Interface2
     ) { super() }

    PrintText(text: string): void {
        const mutatedText: string = this.class2.MutateText(text);
        console.log(mutatedText);
    }

    Addition(x: number, y: number): number {
        return this.Sum(x, y);
    }
}

export interface Interface2 {
    MutateText(text: string): string;
}

@injectable()
export class Class2 implements Interface2 {
    MutateText(text: string): string {
        console.log(`Received text ${text}`);
        return `${text} mutated`;
    }
}

控制器编译的代码看起来几乎一样(当然命名除外)

let Class1 = class Class1 extends baseclass_1.baseClass {
    constructor(class2) {
        super();
        this.class2 = class2;
    }
    PrintText(text) {
        const mutatedText = this.class2.MutateText(text);
        console.log(mutatedText);
    }
    Addition(x, y) {
        return this.Sum(x, y);
    }
};

当我运行这段代码(不是在模拟器中而是在节点中)时,我根本没有收到任何错误,似乎 PrintText 中的这个确实存在。我还将 tsconfig.json 内容从原始项目复制到我尝试隔离错误的项目中,也许它与那里的设置有关,但据我所知,情况并非如此。我被困在错误上,我无法弄清楚是什么导致了错误。有没有人遇到过这种问题或知道我该如何解决?

编辑:添加调用代码

对于原型代码,方法链接到路由。

app.get('/fastget', this.fastGet);

应用程序是 Express 类型:

this.app = express();

app 通过 ApiController 中的 getter 返回,然后添加到 firebase 的 onRequest 中:

const service1Controller: IService1Controller = container.get<IService1Controller>(TYPES.IService1Controller);

export const service1 =  functionsEUWest1.https.onRequest(service1Controller.App); 

这些是类型和容器对象:

类型.ts

let TYPES = {
    //Controllers
    IService1Controller: Symbol("IService1Controller"),

    //BusinessLogics        
    IService1Logic: Symbol("IService1Logic")
}

export default TYPES;

反转配置文件

class ContainerConfig {
    private _container: Container = new Container;

    get Container() { return this._container };

    private configureControllers(container: Container) {
        container.bind(TYPES.IService1Controller).to(Service1Controller);
    }

    private configureBusinessLogics(container: Container) {
        container.bind(TYPES.IService1Logic).to(Service1Logic);
    }

    constructor() {
        this.configureControllers(this._container);
        this.configureBusinessLogics(this._container);
    }
}

export default new ContainerConfig().Container;

对于隔离错误的代码,这是调用代码:

const class1: Interface1 = container.get<Interface1>(TYPES.Interface1);

class1.PrintText("This text is");
const result = class1.Addition(2, 3);

console.log(`Sum of 2 and 3 is ${result}`);

这就是 TYPES 和容器对象的样子:

类型.ts

let TYPES = {
    Interface1: Symbol("Interface1"),
    Interface2: Symbol("Interface2")
}

export default TYPES;

加强.config.ts

const container = new Container();

container.bind(TYPES.Interface1).to(Class1);
container.bind(TYPES.Interface2).to(Class2);

export default container;

标签: typescriptfirebasedependency-injection

解决方案


在做了更多研究之后,似乎在将处理程序传递给 app.get 时,在处理程序中不再知道实现处理程序的类中的 this。用这方面的知识多搜索,发现了下一个话题:

使用 app.get(..) 路由后 Express JS 'this' 未定义

似乎可以对该方法调用 .bind 。解决方案是将其绑定到fastget:

 app.get('/fastget', this.fastGet.bind(this));

一切正常。


推荐阅读