https://github.com/teppeis/closure-ts
異論は認めない。
- M社
- G社
- D社
- H
静的型付け指向ではないライブラリに型定義を与えて使っても型の力は活かせない(古くてごめん)
現存する唯一のフルスタック静的型付けJSライブラリ(当社調べ)
closure-ts: Use Closure Library in TypeScript
- Closure LibraryのJSDocとコードをDoctrineとEsprimaでパースしてTypeScript用の型定義ファイル(d.ts)を吐き出す。
- まだ昨日数時間実装しただけのPoCレベル
- いくつかのファイルは生成に成功
- オリジナル: goog/string/string.js
- 生成した型定義: goog/string/string.d.ts
特徴
- TypeScript, Closure Toolsの既存資産はそのまま活用できる(Powered by IDEs, Grunt, Closure Compiler)
- さまざまなTypeScriptの使い方に対応
- Internal modules
- External modules (AMD/CommonJS)
- 1つのライブラリを全言語で動かす
- Closure Compiler
- TypeScript
- Haxe
- JSX
- Dart?
- Write once, run anyware
- ATD (Abstract Type Definition) ?
- doctrineが既に近いことをやっている
// JSDocの型定義
/**
*@type {Array<string>}
*/
// Doctrineのパース結果
{
"description": "",
"tags": [
{
"title": "type",
"description": null,
"type": {
"type": "TypeApplication",
"expression": {
"type": "NameExpression",
"name": "Array"
},
"applications": [
{
"type": "NameExpression",
"name": "string"
}
]
}
}
]
}
- JSコードをEsprimaがASTで抽象化したように、JSDocの型情報をdocrtineが抽象化する。
- EstraverseのDoctrine版、doctraverse みたいなものが簡単に書ける。
- ただし、Doctrineが抽象化できているのは型情報のみ。
- 型情報の外側に言語依存で仕様が異なるものがたくさんある
- Module
- Interface
- Function
- Class
- Variable
- Generics
- Enum
- UnionType
- Null
- Undefined
- Rest parameters
- ...
- 各言語向けの型定義生成では、結局このレイヤーの泥臭い変換が必要。。
- 例えば以下のコードに対して、doctineは「string型の引数strを1つ取る関数がある」という情報しか扱わない。
mynamespace.foo.bar
がmoduleとvarなのか、オブジェクトとメソッドなのか、intefaceとstaticメソッドなのか、解釈は個別の実装ごとに必要。
- 例えば以下のコードに対して、doctineは「string型の引数strを1つ取る関数がある」という情報しか扱わない。
/**
* @param {string} str
*/
mynamespace.foo.bar = function(str) {};
- すべてnullable(プリミティブも)、non-nullableがない
- UnionTypeがない
@type {number|string}
- オーバーロードを強要される
- d.ts の書き方に流儀がいろいろあって難しい
- 参考: TypeScript Handbook: Writing .d.ts files
- module, interface, declare, exportとかいろいろある
- module var vs. anonymously-typed var vs. interfaced-typed var
- standard class vs. decomposed class
第一部完。次回作にご期待ください。
https://gist.github.com/teppeis/10659631 を消しちゃったのでコピーをpublicにしておく。