Leo
Leo

Reputation: 115

TypeScript: Module x cannot merge with previous declaration of x in a different file

I have a typescript project with a module splitted into multiple files. There is a class with the same name as this module to get nested classes via declaration merging, but the compiler throws errors: Bar.ts(1,1): error TS2188: Module 'Foo' cannot merge with previous declaration of 'Foo' in a different file 'path/to/my/file/Foo.ts'.

file 'Foo.ts'

class Foo {
    constructor() {

    }
}

file 'Bar.ts'

module Foo {
    export class Bar {
        constructor() {

        }
    }
}

I'm compiling with tsc Foo.ts Bar.ts --declaration --out foo.js

My main Problem is, that I want to be able to use var bar = new Bar(); in my Foo-Class, which declaration-merging should provide in my mind (the language specification didn't really help me here). Right now I have to use var bar = new Foo.Bar();, which is very annoying.

Am I doing something wrong or is this a compiler bug?

Btw, --declaration doesn't seem to work, hope this is caused by those errors.

Upvotes: 3

Views: 1443

Answers (2)

Ryan Cavanaugh
Ryan Cavanaugh

Reputation: 220914

Modules and classes can merge under these restrictions:

  1. The module must be after the class
  2. They must be in the same file

If you look at the code generation for this, the reason for rule #1 becomes obvious -- in JavaScript, you can add properties to a function (in this case, a constructor function), but you can't take an existing object and turn it into a function.

#1 is a consequence of #2, because for side-by-side compilation there's no way to enforce that one script loads before the other, and the behavior you'd see if you got the order wrong would be very difficult to debug.

Upvotes: 3

Fenton
Fenton

Reputation: 250822

If your main requirement is to use the shorter new Bar() rather than new Foo.Bar() your best bet is to put them in the same module... if I create a module named Baz, I can extend it in a second file and use the short-hand new Bar() rather than new Baz.Bar();.

Bear in mind that this will create a directional dependency - Bar.ts will need to be loaded before Foo.ts

Bar.ts

module Baz {
    export class Bar {
        constructor() {

        }
    }
}

Foo.ts

module Baz {
    class Foo {
        constructor() {
            var x = new Bar();
        }
    }
}

However, if your main requirement is to be able to create a new Foo() as well as a new Foo.Bar() you can extend the class with a module... but you'll have to call new Foo.Bar() - you can't use the shortened new Bar().

class Foo {
    private x;
    constructor() {
         this.x = new Foo.Bar();
    }

    test() {
        return 'ftest+' + this.x.test();
    }
}

module Foo {
    export class Bar {
        constructor() {

        }

        test() {
            return 'btest';
        }
    }
}

var f = new Foo();
var b = new Foo.Bar();

alert(f.test()); // ftest+btest
alert(b.test()); // btest

Upvotes: 1

Related Questions