EternallyCurious
EternallyCurious

Reputation: 2415

Unable to access objects in Typescript

I am unable to access objects declared within a class in Typescript from functions. Here's what I have:

export class QUestions {

    credentials:mysqlCredentials.MySQLCredentials;
    sqlConnector:mysql.Mysql;

    constructor() {
        this.credentials = new mysqlCredentials.MySQLCredentials('192.168.249.139', 'dev', 'dev', 'test');
        this.sqlConnector = new mysql.Mysql(this.credentials);
    }

    addQuestion(req, res) {
        var q = ...<Lot of code over here> ; 
        this.sqlConnector.query(q, null);  //Error shown for this line
        res.send();
    }
}

Error:
TypeError: Cannot call method 'query' of undefined

If the code is structured as shown above i.e. the sqlConnector variable is defined in the Typescript class, it throws the error. If I place the sqlConnector outside the Typescript class it works fine. I need to fix this as I need the sqlConnector object inside the class.

export class Questions {

    credentials:mysqlCredentials.MySQLCredentials;

    constructor() {
        this.credentials = new mysqlCredentials.MySQLCredentials('192.168.249.139', 'dev', 'dev', 'test');
        sqlConnector = new mysql.Mysql(this.credentials);
    }

    addQuestion(req, res) {
        var q = ...<Lot of code over here> ; 
        sqlConnector.query(q, null);  //Error shown for this line
        res.send();
    }
}

var sqlConnector;

Upvotes: 0

Views: 518

Answers (2)

Adam Moszczyński
Adam Moszczyński

Reputation: 3556

It is also possible to assign class instance to variable, which after compilation will remain within module scope:

var scl:QUestions;
export class QUestions {

    credentials:mysqlCredentials.MySQLCredentials;
    sqlConnector:mysql.Mysql;

    constructor() {
        scl = this;
        this.credentials = new mysqlCredentials.MySQLCredentials('192.168.249.139', 'dev', 'dev', 'test');
        this.sqlConnector = new mysql.Mysql(this.credentials);
    }

    addQuestion(req, res) {
        var q = ...<Lot of code over here> ; 
        scl.sqlConnector.query(q, null); 
        res.send();
    }
}

Be aware though, that it might cause some problems if you have many instances of the QUestions class within single module. Still in most cases should work fine.

Upvotes: 0

Fenton
Fenton

Reputation: 250952

Are you calling the class in a new context (for example using an event handler)?

If so, this becomes the context of the event, not the class context. This is a common JavaScript problem that can happen in TypeScript too.

You can solve the scope issue in a number of ways:

Using an arrow function

If you use an arrow function to assign the function to a member on the Questions class, it will always use the class scope.

export class Questions {

    credentials:mysqlCredentials.MySQLCredentials;
    sqlConnector:mysql.Mysql;

    constructor() {
        this.credentials = new mysqlCredentials.MySQLCredentials('192.168.249.139', 'dev', 'dev', 'test');
        this.sqlConnector = new mysql.Mysql(this.credentials);
    }

    addQuestion = (req, res) => {
        var q = ...<Lot of code over here> ; 
        this.sqlConnector.query(q, null);  //Error shown for this line
        res.send();
    }
}

Using call to set the scope context

This alternative solution means the Questions class doesn't need to be concerned about scope - if you call the method from a different scope context, you simply use call to assign the question instance as the scope.

element.onclick = function () {
    questions.addQuestion.call(questions, argA, argB);
};

Upvotes: 1

Related Questions