0

For example I have the following module

Foo.Bar.ts

export module Foo {
    export class Bar { }
}

And I want to use it in main, which also belongs to the same module

Main.ts

export module Foo {
    class MainBar {
        constructor() { 
            new Bar(); // doesn't work
        }
    }
}

That does not work unless I import Foo.Bar.ts like following
import * as MyFooBar from "./Foo.Bar"; and then use it in this way new MyFooBar.Foo.Bar().

That's seems a bit excessive, and very different from example Java. Tell me is it the only way?

UPDATE:
So I found post, it still doesn't answer my question. And is somewhat what Roy Dictus suggested, but I guess it is the closest answer for my question for now.

Community
  • 1
  • 1
starcorn
  • 8,261
  • 23
  • 83
  • 124

3 Answers3

1

You can write

import {Bar} from "./Foo.Bar";

then use

var newBar = new Bar();
Roy Dictus
  • 32,551
  • 8
  • 60
  • 76
1

TypeScript modules work like ES2015/2017 modules. At the end of the day, modules are files and they're loaded asynchornously.

In the other hand, modules create an scope like the manual module pattern implementation:

Foo = (function() {
    var export = {};
    export.x = 11;
})();

You need to use import because a function scope won't import other files' (i.e. modules) variables, functions, ... classes by default: there should be imported manually.

When you need something from other module, that operation is equivalent to this:

// File1.js
Foo = (function(export) {
    export.x = 11;

    return export;
})(Foo || {});


// File2.js
Foo = (function(export) {
    // You access the "x" variable exported from the other file on the Foo module
    export.pow2 = function() {
        return export.x * export.x;
    };

    return export;
})(Foo || {});

At the end of the day, you can't expect the behavior of a Java *.jar or .NET assembly *.dll, because these runtime environments run the applications or systems on a local machine and the modules are linked during runtime based on hints to local paths. For example, when B.dll requires A.dll at some point, because some class derives a class defined in A.dll, the runtime will load the assembly A.dll into memory.

Sadly, this mechanism isn't still available on JavaScript and TypeScript is transpiled into that target language for now, because your modules are just code files, they're not byte code or an intermediate language.

Maybe there's a hope with WebAssembly!

Matías Fidemraizer
  • 63,804
  • 18
  • 124
  • 206
0

In your code, the first keyword export denotes an ES6 module. And the keyword module should be replaced by namespace since TypeScript 1.5. We can rewrite your code with the new keyword:

// File Foo.Bar.ts
export namespace Foo {
    export class Bar { }
}

If the purpose is to organize the code, it is a bad practice to use namespaces and modules at the same time. You should choose between modules and namespaces.

With ES6 modules

TypeScript supports the syntax of ES6 modules very well:

// File Foo.Bar.ts
export default class Bar { }

// File Main.ts
import Bar from './Foo.Bar';
class MainBar {
    constructor() { 
        new Bar();
    }
}

It is the recommended way. It will work on Node.js (using the commonjs module syntax in compiler options). Or, in a browser, it will work with the help of a bundler like Webpack (see a tutorial here) or a loader like SystemJS (a tutorial here).

For a good introduction to the ES6 modules syntax, read this article.

With namespaces

If you don't work with modules, do not import neither export anything at the top level:

// File Foo.Bar.ts
namespace Foo {
    export class Bar { }
}

// File Main.ts
namespace Foo {
    class MainBar {
        constructor() { 
            new Bar();
        }
    }
}

This code will work on a browser if you load the two generated JavaScript files, or if you concatenate them, for example with uglifyjs.

Paleo
  • 21,831
  • 4
  • 65
  • 76