0

I have the following HTML + TypeScript that tries to instantiate a simple class called Point. When the hyperlink is clicked, I get the following errors against each try/catch clause:

Errors:

  • Cannot read property 'Empty' of undefined.
  • undefined is not a function.
  • undefined is not a function.

HTML:

<!DOCTYPE html>

<html lang="en">
<head>
    <meta charset="utf-8" />
    <title>TypeScript HTML App</title>
    <script src="app.js"></script>
    <script type="text/javascript">
        function Test()
        {
            try { alert(MyLibrary.Point.Empty.ToString()); }
            catch (e) { alert(e.message); }

            try { alert(new MyLibrary.Point(10, 20).ToString()); }
            catch (e) { alert(e.message); }

            try { alert(MyLibrary.Point.FromPoint(new MyLibrary.Point(10, 20)).ToString()); }
            catch (e) { alert(e.message); }
        }
    </script>
</head>
<body>
    <a href="javascript:Test();">Click Me</a>
</body>
</html>

TypeScript:

module MyLibrary
{
    export interface IPoint { X: number; Y: number; ToString(): string; }

    export class Point implements MyLibrary.IPoint
    {
        private _X: number = 0;
        private _Y: number = 0;

        constructor(x: number, y: number)
        {
            this._X = x;
            this._Y = y;
        }

        public get X(): number { return (this._X); }
        public get Y(): number { return (this._Y); }

        public ToString(): string
        {
            return ("{" + this._X.toString() + "," + this._Y.toString() + "}");
        }

        public static FromPoint(point: MyLibrary.Point): MyLibrary.Point
        {
            return (new MyLibrary.Point(point.X, point.Y));
        }

        private static _Empty: MyLibrary.Point = new MyLibrary.Point(0, 0);
        public static get Empty(): MyLibrary.Point { return (MyLibrary.Point._Empty); }
    }
}

The TypeScript compiles fine and the project targets ECMA5. Not sure what is going on under the hood.

UPDATE: The code starts to work if I remove the static properties from the class. Any ideas why that is? the generated JavaScript for the static properties is as follows:

Object.defineProperty(Point, "Empty", {
    get: function ()
    {
        return (MyLibrary.Point._Empty);
    },
    enumerable: true,
    configurable: true
});
Point._Empty = new MyLibrary.Point(0, 0);
3
  • Here are the various ways of managing your TypeScript project so you don't get undefined : youtube.com/watch?v=KDrWLMUY0R0&hd=1 Commented Nov 18, 2013 at 23:02
  • @basarat: I do not have access to YouTube. Is this video available elsewhere? I could probably find it if you tell me the title. Thanks. Commented Nov 19, 2013 at 2:25
  • sorry to hear that, the title is "TypeScript Modules Demystified : Internal, AMD with RequireJS, CommonJS with NodeJS" Commented Nov 19, 2013 at 6:02

2 Answers 2

2

You can't refer to the qualified name of a class inside a module during the initialization of its static members -- the class is not yet available by that name. Change these two lines:

    private static _Empty: MyLibrary.Point = new MyLibrary.Point(0, 0);
    public static get Empty(): MyLibrary.Point { return (MyLibrary.Point._Empty); }

To this

    private static _Empty: MyLibrary.Point = new Point(0, 0);
    public static get Empty(): MyLibrary.Point { return (Point._Empty); }

If you inspect the code generated you can see that the property MyLibrary.Point only gets set after the static initialization of the class occurs. This might be considered a compiler bug.

Sign up to request clarification or add additional context in comments.

3 Comments

Thank you. I was not aware of the fact that constructors cannot be called during static initialization. On another note, why is it considered a better and/or cleaner practice to put static members in a module with the same name. Wouldn't that allow external code to modify the value of Point.Empty since it is now a public variable?
Just listing both options since the module option doesn't have the performance overhead of the getter. Either might be preferable depending on the scenario.
Interesting, I never thought of that. Is that something that maybe the compiler could flag as an error?
1

Judging from the error messages the module MyLibrary is defined at run time but the class Point inside of it is not. I'm guessing the JS file Point is in isn't being loaded.

Because you're not using modules each JS file with classes you want to use has to be referenced at the top your HTML file. Consider using the --out FILE compile option to compile all your classes to a single file so you only need refer to that one file.

2 Comments

Thanks but I don't think this is the case since I can navigate to the app.js file in browser source view. Oddly enough, the code started working when I removed the static property Empty from the class. Any ideas as to what is going on?
Please see the update at the end of the question. I have included the generated JavaScript for the static properties in case it helps.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.