3

I've found a strange bug.

If you have two classes in different files, and for example class B extends class A, and class A has a variable typed B, TypeScript compiles in wrong order with --out main.js command (when you compile whole project into one file). Wrond order results that javascript throws an error: Uncaught TypeError: Cannot read property 'prototype' of undefined This is because class B is earlier in the code than A, and it want to use it.

Here is the simpliest example:

A.ts

///<reference path='B.ts'/>

class A
{
    public b: B;

    constructor()
    {
    }

    init()
    {
        this.b=new B();
    }
}

B.ts

///<reference path='A.ts'/>
class B extends A
{
    constructor()
    {
        super();
    }
}

app.ts

///<reference path='A.ts'/>
var a: A=new A();
a.init();

Generated main.js

var __extends = this.__extends || function (d, b) {
    function __() { this.constructor = d; }
    __.prototype = b.prototype;
    d.prototype = new __();
};
var B = (function (_super) {
    __extends(B, _super);
    function B() {
        _super.call(this);
    }
    return B;
})(A);
var A = (function () {
    function A() {
    }
    A.prototype.init = function () {
        this.b = new B();
    };
    return A;
})();
var a = new A();
a.init();
//@ sourceMappingURL=main.js.map

Is there a workaround?

Cœur
  • 37,241
  • 25
  • 195
  • 267
Grosmar
  • 157
  • 1
  • 2
  • 9

2 Answers2

1

I'm not sure about your circular dependencies. If you want to substitute the classes then the dependencies really ought to be in one direction. Here is an example:

class A {
    constructor(public b: A)
    {
    }
}

class B extends A
{
    constructor()
    {
        super(this);
    }
}

var a = new A(new B());
var b = new B();

Now Your "b.ts" file only needs to depend on the "a.ts" file - not the other way around. Because B extends A, you can pass in an instance of B when you create a new A. Because the dependency is one-directional, TypeScript now has a chance of compiling things in the right order.

Here is a picture to show the dependency issue:enter image description here

Fenton
  • 241,084
  • 71
  • 387
  • 401
  • 1
    This could work, but A must really have to know about class B, because in my real code it will uses it's special properties, so i can't use this method. In javascript if I change the order manually after compiling it works like a charm. – Grosmar Jan 04 '13 at 13:01
  • I've found two workarounds to this problem, but none of it is too good: user Interface instead of the exact class, or you can use type **any** but this is not so good.... – Grosmar Jan 04 '13 at 13:12
  • 1
    Really, you need to kill the dependency issue. Either A can't depend on B, or vice versa. It may be that you need to move away from inheritance and use delegation instead. – Fenton Jan 04 '13 at 13:23
  • In other OOP languages such dependencies allowed, but anyway the worst thing is that compiler can create js code with fatal errors... Thank You anyway! :) – Grosmar Jan 04 '13 at 13:33
0

Use the export statement on the declared typescript module or class or interface, then you can import the desired function, class or whatever. Typescript is throwing an error because the variable you are trying to reference does not exist.

For example:

module API {
    export class Main {
        public name: string;
        public interest: string;

        constructor() {
            this.name = "Someone";
            this.interest = "web technology";
        }

        puts() {
            console.log(this.name, " like", this.interest);
        }
    }
}

..and then you can call the desired function.

import API;
var c = new API.Main();
Endre Simo
  • 11,330
  • 2
  • 40
  • 49
  • For this question, the classes are not wrapped in an internal module, so the `export` keyword isn't required. – Fenton Jan 04 '13 at 12:15