TypeScript の型定義ファイルと仲良くなろう - Hatena Developer Blog は良い解説だが、entity, container がイマイチ不明瞭。
まず、entity とは、型付きの名前(値はない)、または名前と値のペアのどちらか。名前があることを強調したいなら named entity だ。container は entity のリストであり、同名のエンティティが複数在るかも知れない。出現の順番は意味がある。
課題は:
- 特定のエンティティに対して、その親コンテナとは何か?
- 特定のエンティティに対して、そのルートコンテナとは何か?
まず、エンティティの入る“場所”は、名前構造の名前コンテナのパーティション。「パーティション=コンテナ」という用語コンフリクトが起きている。
親コンテナは、エンティティが所属するパーティションを直接含むコンテナ、でいいだろう。
ルートコンテナだが、これは、あるコンテナが「ルートだ」という話ではない。エンティティに対して、そのルートコンテナという概念がある。
- エンティティがプライベートな(エクスポートされてない)なときは、親コンテナがルートコンテナ。
- エンティティがパブリックな(エクスポートされている)ときは、親コンテナのルートコンテナがそのエンティティのルートコンテナ。
以上の定義には、コンテナ自体もエンティティであることが含意される。したがって、コンテナの親コンテナという概念もある。
大域名前空間〈global namespace〉とは、名前コンテナであり、絶対的なルート(相対的なルートや、エンティティのルートコンテナではない)。したがって、大域名前空間=大域コンテナには親コンテナがない。
次の概念が紛らわしい。
- 大域コンテナ=絶対的なルートコンテナ
- エンティティのルートコンテナ
- 相対的なルートコンテナ 例:モジュールのルートコンテナ
TypeScriptの場合、namespace は自動的にパブリックになるようだ。したがって、namespaceが記述されたモジュールスコープから飛び出して大域コンテナ内に名前空間名が配置される。
同様に、interfaceも自動的にパブリックになり、パブリックなinterfaceならそのスコープはファイルモジュールから飛び出す。さらにオープンエンドであることから、他のファイルでインターフェイスの内容を足すことが出来る。
interfaceがオープンエンドでクローズドじゃないのは奇妙な感じがするが、柔軟性を確保するためにしょうがないのだろう。モンキーパッチじゃなくて、コンパイル時の動的パッチのようなものが出来る。モルモットパッチくらい?
[追記]TypeScriptの場合、.tsファイルがモジュールかスクリプトかはimport/export宣言のあるなしで区別して、スクリプトの場合は、大域コンテナ〈大域名前空間〉に直接貼り付ける感じになる。モジュールだと、モジュールのスコープを作ってシールドする。シールドがあるかないかがモジュールとスクリプトの差異。[/追記]