ts2kt を Gradle で実行する
概要
TypeScript の型定義を Kotlin ファイルに変換する Node.js スクリプトである ts2kt を Gradle で実行できるようにします。
2017/8/31 現在、ts2kt は使える状態ではありません。 生成された Kotlin ファイルでは多数のエラーが発生します。
目次
確認環境
- IntelliJ IDEA Community 2017.2
- Kotlin 1.1.4-2
- Gradle 3.5
- Groovy 2.4.10
参考情報
- gradle-node-plugin/docs at master · srs/gradle-node-plugin · GitHub
- gradle-node-plugin の文書
- GitHub - Kotlin/ts2kt: Converter of TypeScript definition files to Kotlin declarations (stubs)
- ts2kt の文書
解説
例として Vue.js の型情報 (*.d.ts
) を Kotlin ファイル (*.kt
) に変換する。
手順としては以下の通り。
- node をプロジェクト用にダウンロード
- npm を使い ts2kt と vue をインストール
- ts2kt で
*.d.ts
を*.kt
に変換
まずは build.gradle
を以下の通りに記述する。
buildscript { ext.gradle_node_version = '1.2.0' repositories { jcenter() maven { // gradle-node-plugin url "https://plugins.gradle.org/m2/" } } dependencies { classpath "com.moowork.gradle:gradle-node-plugin:$gradle_node_version" } } apply plugin: 'com.moowork.node' node { // node をプロジェクト用にダウンロード download = true } task ts2kt(type: NodeTask) { String nodeDir = "${project.projectDir}/node_modules" script = file("$nodeDir/ts2kt/ts2kt.js") String destDir = 'src/main/kotlin/org/vuejs' file(destDir).mkdir() args = ['-d', destDir] + file("$nodeDir/vue/types").listFiles().collect { it.absolutePath } }
npm の設定として pakage.json
を以下の通りに記述する。
{ "name": "Vue.kt", "version": "2.4.2", "description": "Vue.kt that is Vue.js in Kotlin", "devDependencies": { "ts2kt": "0.0.14", "vue": "2.4.2" } }
設定が完了したら以下のコマンドを実行する。
$ ./gradlew npmInstall ts2kt
src/main/kotlin/org/vuejs
ディレクトリに Kotlin ファイルが生成される。
例えば vue.kt
の一部。
external interface `T$0` { @nativeInvoke operator fun invoke(): VNode @nativeInvoke operator fun invoke(tag: String, children: VNodeChildren): VNode @nativeInvoke operator fun invoke(tag: String, data: VNodeData? = definedExternally /* null */, children: VNodeChildren? = definedExternally /* null */): VNode @nativeInvoke operator fun invoke(tag: Component, children: VNodeChildren): VNode @nativeInvoke operator fun invoke(tag: Component, data: VNodeData? = definedExternally /* null */, children: VNodeChildren? = definedExternally /* null */): VNode @nativeInvoke operator fun invoke(tag: AsyncComponent, children: VNodeChildren): VNode @nativeInvoke operator fun invoke(tag: AsyncComponent, data: VNodeData? = definedExternally /* null */, children: VNodeChildren? = definedExternally /* null */): VNode } ... <snip> ... open fun <T> `$watch`(expOrFn: (this: Vue /* this */) -> T, callback: WatchHandler<Vue /* this */, T>, options: WatchOptions? = definedExternally /* null */): () -> Unit = definedExternally ... <snip> ...
元は vue.d.ts
のこの部分。
export type CreateElement = { // empty node (): VNode; // element or component name (tag: string, children: VNodeChildren): VNode; (tag: string, data?: VNodeData, children?: VNodeChildren): VNode; // component constructor or options (tag: Component, children: VNodeChildren): VNode; (tag: Component, data?: VNodeData, children?: VNodeChildren): VNode; // async component (tag: AsyncComponent, children: VNodeChildren): VNode; (tag: AsyncComponent, data?: VNodeData, children?: VNodeChildren): VNode; } ... <snip> ... $watch<T>( expOrFn: (this: this) => T, callback: WatchHandler<this, T>, options?: WatchOptions ): (() => void); ... <snip> ...
生成された Kotlin ファイルにはいくつか問題がある。
T$0
という名前が同一パッケージ内で複数定義されることになり名前が衝突する。@nativeInvoke
は DeprecatedVNodeChildren
,Component
,AsyncComponent
などの型が定義できていない- Union Type に対応できていないため型を定義できない
- パラメータ名に
this
(Kotlin のキーワード) が使われている
Union Type に関する議論はされている様子。
既存の JavaScript ライブラリを使うのであれば ts2kt による型情報を補足が欲しいところ。