簡単な関数をCLIで作ってみよう

JavaScriptからTypeScriptへのマイグレーションは想像以上に簡単なこと、コンパイラが生成するJSコードがどんなものなのか、コンパイラがあることのメリットを体感してもらう

JavaScriptで発生しうる問題

JavaScriptで以下のような関数があったとします。

function increment(num) {
return num + 1;
}
console.log(increment(1));

ただの引数を+1して返すだけのその名もincrementです。

上記をペーストして実行します。 実行時のファイル名をincrement.jsとしていますが、異なる名前にした方は読みかえてください。

$ node increment.js
2

予想通りのなんでもない関数ですが、この関数が以下のように呼ばれたらどうでしょうか。

function increment(num) {
return num + 1;
}
console.log(increment('1'));

呼び出し時の1'1'になりました。これだけでこの関数の結果は大きく変わってしまいます。

$ node increment.js
11

これは算術演算子の+(加算)を期待してこの関数を作ったと思われるところに文字列が入ってしまったため、+が文字列連結として解釈されてしまったことが原因です。 もしこれが金額の計算だったとしたら大変なことになります。

TypeScriptを使うと、コーディングの時点でこのような型の不一致による意図しない挙動を抑えられるようになります。

JavaScriptをTypeScriptに変換する

変更は拡張子を.jsから.ts に変更するだけです。

$ mv increment.js increment.ts

これをエディタで開くとincrement()の引数にあたるnumのところで何か言われます。

Parameter 'num' implicitly has an 'any' type, ...

これは、TypeScriptはこの引数に対していかなる型情報も与えられていない(いわゆるany)よということを言っています。そこで型を付加します。付加する型はnumber型です。

function increment(num: number) {
return num + 1;
}
console.log(increment('1'));

すると今度は呼び出し側の引数でTypeScriptコンパイラからメッセージが表示されます。

Argument of type '"1"' is not assignable to parameter of type 'number'.`

このメッセージの意味は、「この引数の'1'number型ではないよ」という至極まっとうな指摘です。

ひとまずこの警告を完全無視してトランスパイルをしてみます。

$ tsc increment.ts

するとやはり警告が出てしまいます。

Argument of type '"1"' is not assignable to parameter of type 'number'.
console.log(increment('1'));
~~~
Found 1 error.

このように事前にコードに潜んでいる危険を、コーディングまたはトランスパイルの時点で検知できます。

戻り値にも型を書く

今回は引数のみの紹介となりましたが、戻り値にも型を指定することができます。これによりその関数内で意図しない結果を返さないかどうかの検知に使うことができます。

戻り値も書いたincrement.tsの完全版は以下のようになります。

function increment(num: number): number {
return num + 1;
}

もちろん、この関数で戻り値をstring型などnumber型ではない型に設定するとTypeScriptから指摘を受けます。

Type 'number' is not assignable to type 'string'.
return num + 1;
~~~~~~~~~~~~~~~