Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TypeScript class function not available

I'm trying to call a instance method of a TypeScript class (in an ASP.NET MVC project). However, at Runtime I get exceptions like 0x800a01b6 - JavaScript runtime error: Object doesn't support property or method 'checkString'.

I copied the generated JavaScript in a jsfiddle where the method seems to work.
I'm not really a JavaScript guy, so any help is much appreciated!

Things I have tried so far:

  1. different browsers (Chrome: Uncaught TypeError: undefined is not a function, FF: TypeError: this.checkString is not a function)
  2. clearing browser caches
  3. deleting the temporary files of IIS Express
  4. cleaning and rebuilding the solution
  5. not using the private modifier
  6. starting the project on another machine
  7. replacing the underscore.js call with a dummy to verfiy that's not the problem
  8. checked that the instance members are correctly set

This is the TypeScript code:

class FormData {
    BlogName: string;
    CacheTimeOut: number;
    CopyrightHolder: string;
    NavBarTitle: string;
    MarkdownExtra: boolean;
    MarkdownSanitize: boolean;
    RatingActive: boolean;
    HtmlEditor: boolean;

    constructor(blogName: string, cacheTimeOut: number, copyrightHolder: string, navBarTitle: string, markdownExtra: boolean, markdownSanitize: boolean, ratingActive: boolean, htmlEditor: boolean) {
        this.BlogName = blogName;
        this.CacheTimeOut = cacheTimeOut;
        this.CopyrightHolder = copyrightHolder;
        this.NavBarTitle = navBarTitle;
        this.MarkdownExtra = markdownExtra;
        this.MarkdownSanitize = markdownSanitize;
        this.RatingActive = ratingActive;
        this.HtmlEditor = htmlEditor;
    }

    private checkString(value: string): boolean {
        return _.isString(value) && value !== '';
    }

    validate(): boolean {
        return (this.checkString(this.BlogName) && this.checkString(this.CopyrightHolder) && this.checkString(this.NavBarTitle) && _.isNumber(this.CacheTimeOut) && !_.isNull(this.MarkdownExtra) && !_.isNull(this.MarkdownSanitize) && !_.isNull(this.RatingActive));
    }       
}

//I'm calling the validate function like that (from within the same module)
var form = getFormData(); //returns a FormData instance
if (!form.validate()) {
    //foo
}

And here the generated JavaScript:

var FormData = (function () {
    function FormData(blogName, cacheTimeOut, copyrightHolder, navBarTitle, markdownExtra, markdownSanitize, ratingActive, htmlEditor) {
        this.BlogName = blogName;
        this.CacheTimeOut = cacheTimeOut;
        this.CopyrightHolder = copyrightHolder;
        this.NavBarTitle = navBarTitle;
        this.MarkdownExtra = markdownExtra;
        this.MarkdownSanitize = markdownSanitize;
        this.RatingActive = ratingActive;
        this.HtmlEditor = htmlEditor;
    }
    FormData.prototype.checkString = function (value) {
        return _.isString(value) && value !== '';
    };

    FormData.prototype.validate = function () {
        return (this.checkString(this.BlogName) && this.checkString(this.CopyrightHolder) && this.checkString(this.NavBarTitle) && _.isNumber(this.CacheTimeOut) && !_.isNull(this.MarkdownExtra) && !_.isNull(this.MarkdownSanitize) && !_.isNull(this.RatingActive));
    };
    return FormData;
})();
like image 301
marce Avatar asked Apr 14 '14 11:04

marce


2 Answers

This is probably because of the wrong this at runtime. You can use a lambda function ()=>{} instead of function to make sure that the this is lexically scoped in the generated JavaScript:

validate = (): boolean => {
        return (this.checkString(this.BlogName) && this.checkString(this.CopyrightHolder) && this.checkString(this.NavBarTitle) && _.isNumber(this.CacheTimeOut) && !_.isNull(this.MarkdownExtra) && !_.isNull(this.MarkdownSanitize) && !_.isNull(this.RatingActive));
    } 

Please search for what this means in javascript and typescript to learn more.

like image 58
basarat Avatar answered Oct 04 '22 11:10

basarat


Another Bypass-Style Solution:
instead of using this., you can use super..

  • A prerequisite is to create two classes, one as a Base Class, another as a Usable Class.
  • The Base Class contains the methods that you want to call in the constructor.
  • The Usable Class calls the Method from within it's constructor using super.myMethod(); instead of this.myMethod();

This is a subtle benefit made easily possible thanks to Typescript. :)

Example:
Source: Typescript Bypass Solution on Stackoverflow

export class myBaseClass
{
    constructor(ctx:any)
    {
        this.ctx = ctx;         // Audio context saved into member variable of class
    }
    myBaseMethod()
    {
        // Do Complex Work
    }
}

export class myUsableClass extends myBaseClass
{
    constructor(ctx:any)
    {
        super(ctx);
        super.myBaseMethod(); // Use super., Not this.
    }

}
like image 43
JThora Avatar answered Oct 04 '22 10:10

JThora