Reputation: 2775
Can you help me out - is this a bug or am I misunderstanding the documentation?
I have two files in a namespace - you'll find a simpler version below.
The Typescript docs state that "Even though the files are separate, they can each contribute to the same namespace and can be consumed as if they were all defined in one". Therefore I would assume that a class from one file could access another file from within the same namespace even if it was not exported. (Because that would be the case if they were defined in the same place)
However, tsc complains that it can't find the name "Dispatcher". Why does this happen? Am I misunderstanding the documentation at this point? Or is it just a compiler bug? Would be a shame if it was the former, because namespace only visibility would help a lot for unit testing and encapsulating.
Code:
(code changed for simplicity. If syntax errors are present, they are caused by that):
Application.ts:
/// <reference path="Dispatcher.ts"/>
namespace Application {
export class Application {
constructor() {
new Dispatcher();
}
}
}
Dispatcher.ts:
namespace Application {
class Dispatcher { /* ... */ }
}
Upvotes: 4
Views: 1229
Reputation: 51629
The Typescript docs state that "Even though the files are separate, they can each contribute to the same namespace and can be consumed as if they were all defined in one".
It depends on the precise definition of "contribute to the same namespace". Current interpretation is "anything exported is available anywhere, anything not exported is available only inside the namespace part where it's defined". This is how it's explained in the language specification:
Namespaces provide a mechanism for organizing code and declarations in hierarchies of named containers. Namespaces have named members that each denote a value, a type, or a namespace, or some combination thereof, and those members may be local or exported. The body of a namespace corresponds to a function that is executed once, thereby providing a mechanism for maintaining local state with assured isolation. Namespaces can be thought of as a formalization of the immediately-invoked function expression (IIFE) pattern.
If there are several declarations of the same namespace, each one is compiled into a separate IIFE, as can be seen in compiled javascript code for Dispatcher.ts
:
var Application;
(function (Application) {
class Dispatcher {
}
})(Application || (Application = {}));
The result is that Dispatcher
is scoped inside the function, and it's not accessible from the outside.
Even if you had namespace Application
repeated twice in the same file, each would be defining its own copy of Dispatcher
- there is no error for this code:
namespace Application {
class Dispatcher { /* ... */ }
}
namespace Application {
class Dispatcher { /* ... */ }
}
The only way to make Dispatcher
accessible from outside namespace { ... }
is to export it. With export, Dispatcher
becomes a property of Application
object:
namespace Application {
export class Dispatcher { /* ... */ }
}
compiled code:
var Application;
(function (Application) {
class Dispatcher {
}
Application.Dispatcher = Dispatcher;
})(Application || (Application = {}));
This behavior makes sense implementation-wise. It would be really troublesome to implement namespace so that un-exported objects were shared among all namespace instances, but not accessible from outside.
Upvotes: 6