新ライブラリのHegelは、JavaScriptで高度な静的型チェックを実現しようという試みだ。強い型推測と完全な型システムを提供するという。現在はまだアルファ版だが、専用のオンライン・プレイグラウンドで動作を確かめることができる。
Hegelは型アノテーションを備えたJavaScript用の型チェッカである。TypeScriptの場合のように、新たなプログラム言語構造を学ぶ必要はないが、アノテーション記法についての学習は必要だ。Hegelは強い、完全な型システム(Sound File System)を使うことで、実行時の型エラーを防止する。
const numbers: Array<number> = [];
// HegelError: Type "Array<number>" is incompatible with type "Array<number | string>"
const numbersOrStrings: Array<string | number> = numbers;
numbersOrStrings[1] = "Hello, TypeError!";
// HegelError: Property "toFixed" does not exist in "Number | undefined"
numbers[1].toFixed(1);
上記のコードをTypeScript(v3.8.3)でコンパイルしてもエラーにならないが、実行時にはエラーが発生する可能性がある。
完全な型システムと合わせて、Hegelでは、強力な型推論を設計目標にしている。
// Hegel will infer "promisify" as "<_q, _c>((_c) => _q) => (_c) => Promise<_q>"
const promisify = fn => arg => Promise.resolve(fn(arg));
// There, Hegel will infer "<_c>(_c) => Promise<_c>"
const id = promisify(x => x);
// And "upperStr" will be inferred as "Promise<string>"
const upperStr = id("It will be inferred").then(str => str.toUpperCase());
// Finally, "twiceNum" will be inferred as "Promise<number>"
const twicedNum = id(42).then(num => num ** 2);
同じ例をTypeScript(version 3.7.5でテスト)で実行すると、3つのエラーが検出されて、result
の値としてPromise<any>
型が推測される。結果的に強力な型推論は、コードに対するアノテーション記述の必要性を低減してくれるのだ。その上に、可読性が向上することも少なくない。
Hegelは例外にも型付けを行う。
function assert(age) {
if (typeof age !== "number") {
throw new TypeError("Age is not number.");
}
if (age <= 0) {
throw new ReferenceError("Age can't be less or equals zero.");
}
}
try {
assert(0);
} catch(error) {
// The "error" variable will be typed as "ReferenceError | TypeError | unknown"
}
Hegelの完全な型システムの副産物は、型強制(type coercion)とany
型のないことだ。
// Error: There is no "any" type in Hegel.
const something: any = null;
// Error: Type cast does not exist in Hegel
(null: any).call();
Hegelのドキュメントには、おもな代替プロダクトであるTypeScriptとFlowとの比較が含まれている。標準型(プリミティブ、関数、オブジェクト、クラス、配列)に加えて、Hegelの型システムは、unknown型(JSON.parse()
などによって返される)、optional型、union型、tuple型、generic型、magic型といった型を揃えている。
magic型は、既存の型から新たな型を取得ないし生成する場合に使用される。型を取って別の型に変更する関数のようなものだ。Hegelは17のmagic型を定義している。$Exclude magic型(TypeScriptの等価機能であるExclude型と同じようなセマンティクスを持つ)の例は、次のようなものになる。
type Status = "Ok" | "Failed" | "Pending" | "Canceled";
// IntermediateStatuses = "Canceled" | "Panding"
type IntermediateStatuses = $Exclude<Status, "Ok" | "Failed">;
const intermediateStatuses: Array<$Exclude<Status, "Ok" | "Failed">> = ["Pending", "Canceled"];
// Error: Type "['Failed']" is incompatible with type "...Array<'Canceled' | 'Pending'>"
intermediateStatuses.push("Failed");
@parcdljsの著者であるDavon Govett氏は、Twitterで次のように応えている。
とても面白いと思います!TSよりもFlowに近く、しかもJSを実装しているのですからね。型推論や完全性、JSの型のみ(その他の機能はなし)に注目していること、.d.tsのサポート、vscodeの統合など。
Hegelはnpmで配布され、コマンドラインインターフェースとインタラクティブなオンラインプレイグラウンドが添付されている。動作には最新バージョンのnode.js(>12)が必要だ。インストール方法はGitHubリポジトリに説明されている。
HegelはMITライセンスされている。フィードバックとコントリビューションの受付と提供は、GitHubプロジェクト経由で行われる。作者によると、
Hegelはコミュニティのために、コミュニティが開発しました。ですから、PRやイシューが無視されたり、飛ばされることはありません。