これさえやれば大丈夫! TypeScriptのImportが取っ付きにくい人向け
(2014/6/1追記) 本記事はTypeScriptに対する知識が浅いうちに生意気にも書いた記事ですが、TypeScriptのimport
はクライアントサイド(ブラウザ)向けとサーバサイド(Node.jsなどのCommonJS)向けで解釈が異なり、このためコンパイラtsc
へのオプション指示が必要になります。以下の本文で「コンパイラに対するオプションを与えないと怒られる」と書いたのはクライアント向けとサーバ向けの情報を混ぜて勘違いした結果です。
以下は、クライアントサイド向けとしてimport
を使う際に書いた古い記事です。コメント欄にも有益な情報を頂いておりますので、併せてご参照ください。
TypeScriptによってJavaScriptもずいぶん書きやすくなりました。OOPとしてグローバル変数や静的関数は極力減らしたいところですが、jQueryなどのJavaScript資産を併用すると、まだまだそうもいきません。
そこで名前空間に相当するTypeScriptのmodule
を活用してソースファイルをスマートに個別管理しましょう。
moduleを使う上での問題点
- ハマる。最初は何をしていいのか全然分からない。
- どうも
export
とかimport
があるっぽい。 - 検索で出たありがたい情報を元にやってみても やたらとコンパイラに怒られる。
どうもmodule()
もrequire()
も仕様が微妙なようで今後どうなるか正直分かりません。コンパイラに対するオプションを与えないと怒られるなど使い勝手もイマイチな印象。
解決法
四の五の言わず、公式ドキュメント(PDF) "10.3 Import Declarations"を読めば一発で解決しました。実験を重ねたのでその結果を記しておきます。
-
module
宣言を使う。 - 外部ファイルで使いたいもの(クラス、関数、変数、インタフェースなど)に
export
を宣言。 - モジュール外や別のモジュール内で
import
を使い呼び出す。 -
module()
もrequire()
も使わない。
module modA {
export class clsA {
n: number;
constructor(n: number)
{
this.n = n;
}
times(x: number): number
{
return this.n * x;
}
}
}
/// <reference path="moduleA.ts"/>
module modB {
import clsA = modA.clsA;
export function run(): void
{
var obj: clsA = new clsA(5);
var times: number = obj.times(2);
alert(String(times));
}
}
modB.run();
おそらくTypeScript経験者であれば上記ソースだけで何をしているか理解頂けると思います。import
するとき実はimport clsA = modA.clsA;
で十分なようで、複雑そうなrequire()
は使っていません。
ちなみにこのimport
、後述のjsソースでも分かる通り、ただのvar
です。
注意点
module
全体をexportしようとしてexport module
とすると怒られます。require()
はこの場面で意義が出てくるようですが、スコープを絞る意味でも各関数、クラスごとにexport
宣言したほうが理解しやすいと感じます。他言語でいうpublic
とprivate
を使い分ける感覚です。
TypeScript言語仕様にもprivate
はありますが、あれはコンパイラに対する指示であって、js変換後は結局どこからでも呼んでこれるので、スコープを限定するmodule
とexport
の組み合わせのほうが良い気がしています。
おまけ
最後に、これをJavaScriptに変換したあとのソースも貼っておきます。
var modA;
(function (modA) {
var clsA = (function () {
function clsA(n) {
this.n = n;
}
clsA.prototype.times = function (x) {
return this.n * x;
};
return clsA;
})();
modA.clsA = clsA;
})(modA || (modA = {}));
/// <reference path="moduleA.ts"/>
var modB;
(function (modB) {
var clsA = modA.clsA;
function run() {
var obj = new clsA(5);
var times = obj.times(2);
alert(String(times));
}
modB.run = run;
})(modB || (modB = {}));
modB.run();
すごいね。
Discussion