2016年12月11日

初めてのTypeScript (6) - モジュールのimport/export

   このエントリーをはてなブックマークに追加 Clip to Evernote

これは TypeScript Advent Calendar 2016 の11日目の記事です。 


初めてのTypeScript (4) - classをし別ファイルから利用してみる」で挫折したexport/importに再挑戦します。

今度は、前回構築したVisual Studio Code+TypeScriptの環境を使います(mode.jsを使っている)ので、ブラウザのような制限は受けないはずです。

tsconfig.json, tasks.json, launch.jsonは、基本的にそのまま利用したいので、TypeScriptのソースファイルが入っているフォルダごとコピーして、新しいプロジェクトとします。

TypeScriptのnamespaceは使わない

いろいろ試行錯誤した結果ですが、「TypeScriptでnamespaceは使わない」が現時点での僕の結論です。

C#プログラマーからすると、「なんで?」と思うのですが、モジュールの概念が微妙に違うので、TypeScriptにおいては、namespaceは意味がないという結論にたどり着きました。

それと、詳細は割愛しますが、C#の感覚で複数のファイルに同じnamespace名を付けると、importする側では、名前が重複した状態になりビルドできません。 無理やりビルドエラーを取ろうと頑張ると、何のためのnamespaceかが全く分からないカオス状態になります。

ブラウザ環境でもたぶん同じ状況になるのだと思います(すいません、これは確かめていません)。

モジュールのexport

では、「初めてのTypeScript (4)」と同じように、Utils.tsファイルを定義します。

    export class Stopwatch {
        private startTime: number;
        private stopTime: number;

        static startNew(): Stopwatch {
            let sw = new Stopwatch();
            sw.start();
            return sw;
        }

        start() {
            this.startTime = Date.now();
        }

        stop() {
            this.stopTime = Date.now();
        }

        elapsed(): number {
            return this.stopTime - this.startTime;
        }

        toString(): string {
            let tms = this.elapsed();
            let h = Math.floor(tms / (1000 * 60 * 60));
            let m = Math.floor(tms / (1000 * 60));
            let s = Math.floor(tms / 1000);
            let ms = Math.floor(tms % 1000);
            return `${this._zeroPadding(h)}:${this._zeroPadding(m)}:${this._zeroPadding(s)}:${this._zeroPadding(ms, 3)}`;
        }

        private _zeroPadding(n: number, d: number = 2): string {
            let zero = '';
            for (let i = 1; i < d; i++)
                zero += '0';
            return (zero + n).slice(-d);
        }
    }

これを utils.ts というファイル名で保存します。

モジュールのimport

では、このutils.tsをimportしてみます。

import * as Utils from './utils';

こうすると、同一フォルダにある utils.tsをimportしてくれます。

これで、

let sw = Utils.Stopwatch.startNew();

のような記述が可能になります。

Stopwatchの前のUtils.を省略したいならば、

import * as Utils from './utils';
import Stopwatch = Utils.Stopwatch;

のような書けばよいみたいです。ちなみに、最後の行は、次のコードと基本的には同じ意味だと考えてもらって差し支えないかなと思います。

const Stopwatch = Utils.Stopwatch;

メインプログラムを書く

utils.tsに定義してあるクラスを利用するコードを書いてみました。

import * as Utils from './utils';

class Solver {
    exec(maxnum: number): number {
        return maxnum;
    }
}

class Application {
    static run(): void {
        let sw = Utils.Stopwatch.startNew();
        try {
            let p = new Solver();
            let n = p.exec(100000);
            console.log(n);
        } finally {
            sw.stop();
            console.log(sw.toString());
        }
    }
}

Application.run();

これを ProjectEuler.ts というファイルで保存します。

Shift+Command+Bでビルドします。

無事ビルドできました。

launch.json の書き換え。

一か所だけ、launch.json の書き換えが必要です。以下のように起動するプログラム名を変更します。

 "program": "${workspaceRoot}/ProjectEuler.js",

実行

F5キーで実行します。デバッグコンソールに以下のような出力がされ正しく動いていることが確認できました。

node --debug-brk=16838 --nolazy ProjectEuler.js 
Debugger listening on [::]:16838
100000
00:00:00:021

これから

ProjectEulerという名前でピンときた方もいると思いますが、実は、今まで書いてきた記事は、TypeScriptを使ってProject Eulerの問題を解くための準備みたいなものです。

今回示したコードは、TypeScriptを使ってProjectEulerの問題を解くためのひな型コードとなっています。最初は、ブラウザで動作するプログラムでコードを書こうと考えていたのですが、途中方向転換し、Node.js上で動かすこととにしました。

TypeScriptを学習するために題材としてProject Eulerを選んだので、10問程度を解ければよいかなと今は考えています。

ということで、次回からは、TypeScriptでProjectEulerに挑戦していこうと思っています。 といっても、あと少ししたら来年出版予定のC#の本の執筆作業のラストスパートで忙しい時期に突入してしまうので、どうなることやら...



 

この記事へのトラックバックURL

http://trackback.blogsys.jp/livedoor/gushwell/52480133