(RESOLVED) Typescript / MQTT / Node - How to acces class member from a callback function?

I'm making an app to manage some smart lights in my house.

I've created a really simple Broker class.

import * as aedes from 'aedes';
import * as net from 'net';

export class Broker {

    aedes: aedes.Aedes;
    broker: net.Server;
    port: number;

    constructor(port: number){
        this.aedes = aedes();
        this.broker = net.createServer(this.aedes.handle);
        this.port = port;
        this.broker.listen(this.port, () => {
            console.log('MQTT is listening.');
        });
    }
    
    /** 
     * This is a callback register function
     *
     * Callback function must have a signature of type : function(topic: string, payload: string)
     **/
    onMsgReceived(callback: {(topic: string, payload: string): void}){
        this.aedes.on('publish', (packet, client) => {
            if (packet.cmd != 'publish') return;
            callback(packet.topic, packet.payload.toString());
        });
    }

}

And then, for the example, a Test class.

export Test {
    someVar: string;
    
    constructor(){ }
    
    onMsgReceivedCallback(topic: string, payload: string){
        console.log('Hey, i\'m printed from the test class');
        console.log('And this is some var : ' + this.someVar);
    }
}

And, of course, an index.ts script.

import { Broker } from './broker.ts'
import { Test } from './test.ts'

const broker = new Broker(1883);
const test   = new Test();


broker.onMsgReceived(test.onMsgReceivedCallback);

The problem is that, if in the function test.onMsgReceived I want to call a member of the class like the var someVar, node throw the following error :

TypeError: Cannot read property 'testVar' of undefined

I don't understand how I can go through this error... Do you have an idea ?

1 answer

  • answered 2020-10-16 06:18 Dmytro

    You have to bind the this context of the class instance to a method if you'd like to pass that method as a callback. There are a couple of ways to do this in TypeScript.

    Defining the method using an arrow function:

    export Test {
        someVar: string;
    
        constructor() {}
    
        onMsgReceivedCallback = (topic: string, payload: string) => {
            console.log(`someVar: ${this.someVar}`);
        }
    }
    

    Or binding the method in the constructor:

    export Test {
        someVar: string;
    
        constructor() {
            this.onMsgReceivedCallback = this.onMsgReceivedCallback.bind(this);
        }
    
        onMsgReceivedCallback(topic: string, payload: string) {
            console.log(`someVar: ${this.someVar}`);
        }
    }