JavaScript は弱く型指定された (または動的に型指定された) 言語です。つまり、変数の型は未定義です。
x = 5; // 5 x = x + 'A'; // '5A'
上記のコードでは、変数 x は最初は数値で、その後は文字列になります。これを弱い型と呼びます。
弱い型付けの利点は、柔軟性が高く、非常に簡潔なコードを記述できることです。ただし、大規模なプロジェクトの場合は、システムの複雑さを軽減し、コンパイル時に型エラーを検出し、プログラマーの負担を軽減できるため、強力な型指定の方が有益です。
JavaScriptを強く型付けされた言語にしようとしている人たちがいます。この記事では、強力な型指定が最終的に正式にサポートされるまで、現在利用可能な 3 つのソリューションを紹介します。
1. TypeScript
TypeScriptは、Microsoftが2012年に発表したプログラミング言語で、JavaScriptのスーパーセットであり、JavaScriptにコンパイルして実行することができます。 最大の特徴は、強い型付けとES6クラスをサポートしていることです。
まず、TypeScriptをインストールします。
$ npm install -g typescript
次に、変数の型を指定します。
// greet.ts function greet(person: string) { console.log("Hello, " + person); } greet([0, 1, 2]);
上記は、greet.ts ファイルのコードです。接尾辞 ts は、これが TypeScript コードであることを示します。関数greetのパラメータは文字列として宣言されますが、呼び出されるときは配列が渡されます。
tscコマンドを使ってtsファイルをjsファイルにコンパイルすると、型の不一致エラーがスローされます。
$ tsc greeter.ts greet.ts(5,9): error TS2345: Argument of type 'number[]' is not assignable to parameter of type 'string'.
2. Flowcheck
Flowcheck は、実行時に変数の型が正しいかどうかをチェックできる軽量の型アサーション ライブラリです。
まず、Flowcheckをインストールします。
$ npm install -g flowcheck
次に、変数の型を宣言するスクリプトを書きます。
function sum(a: number, b: number) { return a + b; } sum('hello','world')
次に、次のコマンドを使用して、スクリプトを通常の JavaScript ファイルに変換します。
$ browserify -t flowcheck -t [reactify --strip-types] \ input.js -o output.js
変換されたファイルは以下の通りです。
var _f = require("flowcheck/assert"); function sum(a, b) { _f.check(arguments, _f.arguments([_f.number, _f.number])); return a + b; }
コードにアサーションライブラリが挿入されているのがわかります。各関数が実行される前にアサーションが実行され、型が一致しない場合はエラーが報告されます。
$ node output.js // throw new TypeError(message); ^ TypeError: Expected an instance of number got "hello", context: arguments / [number, number] / 0 Expected an instance of number got "world", context: arguments / [number, number] / 1
3. Flow
Flow は Facebook が 2014 年にリリースした React のソースコードをチェックするための型チェックツールです。
インストールコマンドは以下の通りです。
$ npm install --global flow-bin
インストールが失敗した場合(私の場合はこれです)、自分でソースコードからコンパイルする必要があります。
Flowの使い方はたくさんありますが、いくつかの例だけを紹介します。前に紹介した 2 つのツールは、宣言された型を持つ変数のみをチェックできますが、Flow は変数の型を推測できます。
// hello.js /* @flow */ function foo(x) { return x*10; } foo("Hello, world!");
上記は hello.js ファイルです。ファイルの最初の行は、変数の型を確認するために Flow を使用する必要があることを示すコメントです。
$ flow check hello.js:7:5,19: string This type is incompatible with /hello.js:4:10,13: number
フローチェックコマンドを実行すると、エラーメッセージが表示されます: 関数 foo の予期されるパラメータは数値ですが、実際には文字列です。
Flowでは変数の型宣言もサポートしています。
/* @flow */ function foo(x: string, y: number): string { return x.length * y; } foo("Hello", 42);
もう 1 つの興味深い機能は、Flow が型アノテーションを型宣言に変換できることです。
// annotation.js /** @param {number} x @return {number} */ function square(x) { return x * x; } square(5);
flow portコマンドを実行すると以下の結果が得られます。
$ flow port annotation.js function square(x: number) : number { return x * x; }
Flow の詳細については、「Exploring Flow, Facebook's Type Checker for JavaScript」をご覧ください。