TypeScript 外部モジュールで名前空間を使用するにはどうすればいいですか? 質問する

TypeScript 外部モジュールで名前空間を使用するにはどうすればいいですか? 質問する

コードがいくつかあります:

ベースタイプ.ts

export namespace Living.Things {
  export class Animal {
    move() { /* ... */ }
  }
  export class Plant {
    photosynthesize() { /* ... */ }
  }
}

犬.ts

import b = require('./baseTypes');

export namespace Living.Things {
  // Error, can't find name 'Animal', ??
  export class Dog extends Animal {
    woof() { }
  }
}

ツリー.ts

// Error, can't use the same name twice, ??
import b = require('./baseTypes');
import b = require('./dogs');

namespace Living.Things {
  // Why do I have to write b.Living.Things.Plant instead of b.Plant??
  class Tree extends b.Living.Things.Plant {

  }
}

これは非常にわかりにくいです。 多数の外部モジュールがすべて同じ名前空間 に型を提供するようにしたいのですが、でLiving.Thingsが表示されないなど、まったく機能しないようです。に完全な名前空間名を記述する必要があります。 ファイル間で同じ名前空間の複数のオブジェクトを組み合わせることはできません。 どうすればよいでしょうか?Animaldogs.tsb.Living.Things.Planttree.ts

ベストアンサー1

キャンディカップの例え

バージョン1: キャンディー1杯につき1杯

次のようなコードを書いたとします。

モジュール1.ts

export namespace A {
    export class Twix { ... }
}

モジュール2.ts

export namespace A {
    export class PeanutButterCup { ... }
}

モジュール3.ts

export namespace A {
     export class KitKat { ... }
}

次のセットアップを作成しました:ここに画像の説明を入力してください

各モジュール (紙のシート) には、という名前の独自のカップAがあります。 これは役に立ちません。ここでは実際にキャンディーを整理しているわけではなく、あなたとお菓子の間に追加の手順 (カップから取り出す) を追加しているだけです。


バージョン2: 地球規模の1杯

モジュールを使用していない場合は、次のようなコードを記述します (export宣言がないことに注意してください)。

グローバル1.ts

namespace A {
    export class Twix { ... }
}

グローバル2.ts

namespace A {
    export class PeanutButterCup { ... }
}

グローバル3.ts

namespace A {
     export class KitKat { ... }
}

このAコードは、グローバル スコープにマージされた名前空間を作成します。

ここに画像の説明を入力してください

この設定は便利ですが、モジュールの場合は適用されません (モジュールはグローバル スコープを汚染しないため)。


バージョン3: カップレス

元の例に戻ると、カップA、、AA役に立ちません。代わりに、次のようにコードを記述できます。

モジュール1.ts

export class Twix { ... }

モジュール2.ts

export class PeanutButterCup { ... }

モジュール3.ts

export class KitKat { ... }

次のような画像を作成します。

ここに画像の説明を入力してください

ずっといい!

モジュールで名前空間をどの程度使用したいかまだ考えている場合は、読み進めてください...


これらはあなたが探しているコンセプトではありません

そもそも名前空間が存在する理由の起源に戻り、その理由が外部モジュールにとって意味があるかどうかを調べる必要があります。

組織: 名前空間は、論理的に関連するオブジェクトと型をグループ化するのに便利です。たとえば、C# では、コレクション型はすべて にありますSystem.Collections。型を階層的な名前空間に整理することで、それらの型のユーザーに優れた「発見」エクスペリエンスを提供します。

名前の競合: 名前空間は、名前の衝突を避けるために重要です。たとえば、同じ名前で異なる名前空間を持つ 2 つの型があるとしますMy.Application.Customer.AddFormMy.Application.Order.AddFormすべての識別子が同じルート スコープに存在し、すべてのアセンブリがすべての型を読み込む言語では、すべてを名前空間に含めることが重要です。

これらの理由は外部モジュールでは意味をなすでしょうか?

組織: 外部モジュールは、必然的にファイル システムに既に存在します。パスとファイル名で解決する必要があるため、論理的な組織スキームを使用できます。モジュールを/collections/generic/含むフォルダーを作成できますlist

Name Conflicts: This doesn't apply at all in external modules. Within a module, there's no plausible reason to have two objects with the same name. From the consumption side, the consumer of any given module gets to pick the name that they will use to refer to the module, so accidental naming conflicts are impossible.


Even if you don't believe that those reasons are adequately addressed by how modules work, the "solution" of trying to use namespaces in external modules doesn't even work.

Boxes in Boxes in Boxes

A story:

Your friend Bob calls you up. "I have a great new organization scheme in my house", he says, "come check it out!". Neat, let's go see what Bob has come up with.

You start in the kitchen and open up the pantry. There are 60 different boxes, each labelled "Pantry". You pick a box at random and open it. Inside is a single box labelled "Grains". You open up the "Grains" box and find a single box labelled "Pasta". You open the "Pasta" box and find a single box labelled "Penne". You open this box and find, as you expect, a bag of penne pasta.

Slightly confused, you pick up an adjacent box, also labelled "Pantry". Inside is a single box, again labelled "Grains". You open up the "Grains" box and, again, find a single box labelled "Pasta". You open the "Pasta" box and find a single box, this one is labelled "Rigatoni". You open this box and find... a bag of rigatoni pasta.

"It's great!" says Bob. "Everything is in a namespace!".

"But Bob..." you reply. "Your organization scheme is useless. You have to open up a bunch of boxes to get to anything, and it's not actually any more convenient to find anything than if you had just put everything in one box instead of three. In fact, since your pantry is already sorted shelf-by-shelf, you don't need the boxes at all. Why not just set the pasta on the shelf and pick it up when you need it?"

"You don't understand -- I need to make sure that no one else puts something that doesn't belong in the 'Pantry' namespace. And I've safely organized all my pasta into the Pantry.Grains.Pasta namespace so I can easily find it"

Bob is a very confused man.

Modules are Their Own Box

You've probably had something similar happen in real life: You order a few things on Amazon, and each item shows up in its own box, with a smaller box inside, with your item wrapped in its own packaging. Even if the interior boxes are similar, the shipments are not usefully "combined".

箱の例えで言えば、重要な点は、外部モジュールはそれ自体が箱であるということです。多くの機能を備えた非常に複雑なアイテムかもしれませんが、任意の外部モジュールはそれ自体が箱です。


外部モジュールのガイダンス

「名前空間」を使用する必要がないことがわかったので、モジュールをどのように整理すればよいでしょうか? いくつかのガイドラインと例を以下に示します。

できるだけトップレベルに近い形でエクスポートする

  • 単一のクラスまたは関数のみをエクスポートする場合は、以下を使用しますexport default

マイクラス.ts

export default class SomeType {
  constructor() { ... }
}

マイファンクション

function getThing() { return 'thing'; }
export default getThing;

消費

import t from './MyClass';
import f from './MyFunc';
var x = new t();
console.log(f());

tこれは消費者にとって最適です。消費者は (この場合)好きなように型に名前を付けることができ、オブジェクトを見つけるために余分なドットを付ける必要がありません。

  • 複数のオブジェクトをエクスポートする場合は、すべてを最上位レベルに配置します。

マイシングス

export class SomeType { ... }
export function someFunc() { ... }

消費

import * as m from './MyThings';
var x = new m.SomeType();
var y = m.someFunc();
  • 大量のものをエクスポートする場合にのみ、module/namespaceキーワードを使用する必要があります。

私のラージモジュール.ts

export namespace Animals {
  export class Dog { ... }
  export class Cat { ... }
}
export namespace Plants {
  export class Tree { ... }
}

消費

import { Animals, Plants} from './MyLargeModule';
var x = new Animals.Dog();

赤い旗

以下はすべて、モジュール構造の危険信号です。これらのいずれかがファイルに当てはまる場合は、外部モジュールに名前空間を設定しようとしていないことを再確認してください。

  • export module Foo { ... }最上位レベルの宣言が(Fooすべてを削除して 1 レベル上に移動する)のみのファイル
  • 単一のファイルexport classまたはexport functionexport default
  • トップレベルで同じ内容を持つ複数のファイルexport module Foo {(これらが 1 つに結合されるとは思わないでくださいFoo)

おすすめ記事