名前空間

用語に関する注意: TypeScript 1.5 では、用語が変更されたことに注意することが重要です。「内部モジュール」は現在「名前空間」です。「外部モジュール」は、ECMAScript 2015 の用語(すなわち module X { が現在推奨される namespace X { と同等である)に合わせて、単に「モジュール」と呼ばれるようになりました。

この記事では、TypeScript で名前空間 (以前は「内部モジュール」) を使用してコードを整理するさまざまな方法について概説します。用語に関する注意で述べたように、「内部モジュール」は現在「名前空間」と呼ばれています。また、内部モジュールを宣言するときに module キーワードが使用されていた場所では、代わりに namespace キーワードを使用できます (また、そうすべきです)。これにより、同様の名前の用語を過負荷にして新しいユーザーを混乱させることを回避できます。

最初のステップ

このページ全体で例として使用するプログラムから始めましょう。Webページ上のフォームでユーザーの入力を確認したり、外部から提供されたデータファイルの形式を確認したりするために記述するような、単純な文字列バリデーターの小さなセットを記述しました。

単一ファイル内のバリデーター

ts
interface StringValidator {
isAcceptable(s: string): boolean;
}
let lettersRegexp = /^[A-Za-z]+$/;
let numberRegexp = /^[0-9]+$/;
class LettersOnlyValidator implements StringValidator {
isAcceptable(s: string) {
return lettersRegexp.test(s);
}
}
class ZipCodeValidator implements StringValidator {
isAcceptable(s: string) {
return s.length === 5 && numberRegexp.test(s);
}
}
// Some samples to try
let strings = ["Hello", "98052", "101"];
// Validators to use
let validators: { [s: string]: StringValidator } = {};
validators["ZIP code"] = new ZipCodeValidator();
validators["Letters only"] = new LettersOnlyValidator();
// Show whether each string passed each validator
for (let s of strings) {
for (let name in validators) {
let isMatch = validators[name].isAcceptable(s);
console.log(`'${s}' ${isMatch ? "matches" : "does not match"} '${name}'.`);
}
}

名前空間

バリデーターを追加するにつれて、型を追跡し、他のオブジェクトとの名前の衝突を心配する必要がないように、何らかの組織化スキームが必要になります。グローバル名前空間に異なる名前をたくさん入れる代わりに、オブジェクトを名前空間にまとめましょう。

この例では、すべてのバリデーター関連エンティティを Validation という名前の名前空間に移動します。ここにあるインターフェースとクラスを名前空間外から参照できるようにしたいので、それらに export を付けます。逆に、変数 lettersRegexpnumberRegexp は実装の詳細なので、エクスポートせずに、名前空間外のコードからは見えなくします。ファイルの末尾にあるテストコードでは、名前空間外で使用する場合に型名を修飾する必要があります(例:Validation.LettersOnlyValidator)。

名前空間化されたバリデーター

ts
namespace Validation {
export interface StringValidator {
isAcceptable(s: string): boolean;
}
const lettersRegexp = /^[A-Za-z]+$/;
const numberRegexp = /^[0-9]+$/;
export class LettersOnlyValidator implements StringValidator {
isAcceptable(s: string) {
return lettersRegexp.test(s);
}
}
export class ZipCodeValidator implements StringValidator {
isAcceptable(s: string) {
return s.length === 5 && numberRegexp.test(s);
}
}
}
// Some samples to try
let strings = ["Hello", "98052", "101"];
// Validators to use
let validators: { [s: string]: Validation.StringValidator } = {};
validators["ZIP code"] = new Validation.ZipCodeValidator();
validators["Letters only"] = new Validation.LettersOnlyValidator();
// Show whether each string passed each validator
for (let s of strings) {
for (let name in validators) {
console.log(
`"${s}" - ${
validators[name].isAcceptable(s) ? "matches" : "does not match"
} ${name}`
);
}
}

ファイル間分割

アプリケーションが成長するにつれて、保守を容易にするためにコードを複数のファイルに分割する必要があります。

マルチファイル名前空間

ここでは、Validation 名前空間を複数のファイルに分割します。ファイルは別々ですが、それぞれが同じ名前空間に貢献でき、すべてが1か所で定義されているかのように使用できます。ファイル間に依存関係があるため、ファイル間の関係をコンパイラーに伝えるために参照タグを追加します。それ以外の場合、テストコードは変更されていません。

Validation.ts
ts
namespace Validation {
export interface StringValidator {
isAcceptable(s: string): boolean;
}
}
LettersOnlyValidator.ts
ts
/// <reference path="Validation.ts" />
namespace Validation {
const lettersRegexp = /^[A-Za-z]+$/;
export class LettersOnlyValidator implements StringValidator {
isAcceptable(s: string) {
return lettersRegexp.test(s);
}
}
}
ZipCodeValidator.ts
ts
/// <reference path="Validation.ts" />
namespace Validation {
const numberRegexp = /^[0-9]+$/;
export class ZipCodeValidator implements StringValidator {
isAcceptable(s: string) {
return s.length === 5 && numberRegexp.test(s);
}
}
}
Test.ts
ts
/// <reference path="Validation.ts" />
/// <reference path="LettersOnlyValidator.ts" />
/// <reference path="ZipCodeValidator.ts" />
// Some samples to try
let strings = ["Hello", "98052", "101"];
// Validators to use
let validators: { [s: string]: Validation.StringValidator } = {};
validators["ZIP code"] = new Validation.ZipCodeValidator();
validators["Letters only"] = new Validation.LettersOnlyValidator();
// Show whether each string passed each validator
for (let s of strings) {
for (let name in validators) {
console.log(
`"${s}" - ${
validators[name].isAcceptable(s) ? "matches" : "does not match"
} ${name}`
);
}
}

複数のファイルが関係する場合、コンパイルされたコードがすべてロードされるようにする必要があります。これには2つの方法があります。

まず、outFileオプションを使用して、すべての入力ファイルを単一のJavaScript出力ファイルにコンパイルすることで、連結された出力を使用できます。

tsc --outFile sample.js Test.ts

コンパイラは、ファイルに存在する参照タグに基づいて、出力ファイルの順序を自動的に決定します。各ファイルを個別に指定することもできます。

tsc --outFile sample.js Validation.ts LettersOnlyValidator.ts ZipCodeValidator.ts Test.ts

または、ファイルごとのコンパイル(デフォルト)を使用して、入力ファイルごとに1つのJavaScriptファイルを出力できます。複数のJSファイルが生成される場合は、ウェブページで<script>タグを使用して、出力された各ファイルを適切な順序でロードする必要があります。たとえば、次のようになります。

MyTestPage.html (抜粋)
html
<script src="Validation.js" type="text/javascript" />
<script src="LettersOnlyValidator.js" type="text/javascript" />
<script src="ZipCodeValidator.js" type="text/javascript" />
<script src="Test.js" type="text/javascript" />

エイリアス

名前空間の操作を簡略化するもう1つの方法は、import q = x.y.zを使用して、よく使用されるオブジェクトの短い名前を作成することです。モジュールをロードするために使用されるimport x = require("name")構文と混同しないでください。この構文は、指定されたシンボルのエイリアスを作成するだけです。モジュールインポートから作成されたオブジェクトを含め、あらゆる種類の識別子に対して、このようなインポート(一般にエイリアスと呼ばれます)を使用できます。

ts
namespace Shapes {
export namespace Polygons {
export class Triangle {}
export class Square {}
}
}
import polygons = Shapes.Polygons;
let sq = new polygons.Square(); // Same as 'new Shapes.Polygons.Square()'

requireキーワードを使用していないことに注意してください。代わりに、インポートするシンボルの完全修飾名から直接割り当てています。これはvarの使用に似ていますが、インポートされたシンボルの型と名前空間の意味でも機能します。重要なのは、値の場合、importは元のシンボルとは異なる参照であるため、エイリアス化されたvarへの変更は元の変数には反映されません。

他のJavaScriptライブラリとの連携

TypeScriptで記述されていないライブラリの形状を記述するには、ライブラリが公開するAPIを宣言する必要があります。ほとんどのJavaScriptライブラリはいくつかのトップレベルオブジェクトのみを公開するため、名前空間はそれらを表現するのに適した方法です。

実装を定義しない宣言を「環境」と呼びます。通常、これらは.d.tsファイルで定義されます。C/C++に詳しい場合は、これらを.hファイルと考えることができます。いくつかの例を見てみましょう。

環境名前空間

人気のライブラリD3は、その機能をd3というグローバルオブジェクトで定義しています。このライブラリは(モジュールローダーではなく)<script>タグを介してロードされるため、その宣言では名前空間を使用してその形状を定義します。TypeScriptコンパイラがこの形状を認識できるように、環境名前空間宣言を使用します。たとえば、次のように書き始めることができます。

D3.d.ts(簡略化された抜粋)
ts
declare namespace D3 {
export interface Selectors {
select: {
(selector: string): Selection;
(element: EventTarget): Selection;
};
}
export interface Event {
x: number;
y: number;
}
export interface Base extends Selectors {
event: Event;
}
}
declare var d3: D3.Base;

TypeScriptドキュメントはオープンソースプロジェクトです。これらのページの改善にご協力ください プルリクエストを送信して

このページの貢献者
MHMohamed Hegazy (56)
OTOrta Therox (15)
DRDaniel Rosenwasser (3)
IOIván Ovejero (1)
JBJack Bates (1)
14+

最終更新日: 2024年3月21日