Scala.js用の型定義をラクに得る scala-js-ts-importer の紹介

最近、仕事で使っている&趣味で貢献している scala-js-ts-importer というOSSの紹介をする。この記事は Qiitaで開催されているScala Advent Calendar 2017の6日目 でもある。

Scala.jsを仕事で使い始めた

今年に入って仕事で開発・運用している SaaS は、フロントエンドもバックエンドも Scala.jsで開発している。

バックエンドを Scala でなく Scala.js にしたのは、Scala言語の良さを活かしつつ、
  • Lambda のランタイムとして省メモリで立ち上げが速い nodejs を使い、コンピューティング料金を節約したかった
  • デプロイする ZIP の50MB制限を回避したかった 
からだ。背景は10月に名古屋で行われた JAWS-UG にて、 Scala.js で AWS Lambda 開発 としてLTした。

静的型付けaltJSの良さ

Scala.jsを初めとした静的型付け系 altJS では、静的な型情報があることで次のような恩恵が得られる。
  • 関数に何を渡せばいいかが型で分かったりする。
  • オブジェクトが持っているメンバーを入力補完できる。
  • メソッドのシグネチャを変えたときに修正を必要とする箇所がすぐ分かる。
しかし残念ながら、JavaScriptで書かれたライブラリには普通、静的な型定義はついていない。ではどうするか?

JSライブラリに型をつける

Scala.jsやTypescriptなどの静的片付け系 altJS では、JSライブラリに外部から型定義を与える仕組みがある。これにより、JSライブラリを静的に型検査できるようになる。

Scala.jsでは、以下のようなメジャーなフロントエンド用JSライブラリには型定義が公開されている。
  • UIフレームワーク:jQuery, Bootstrap, React, Angular, Vue
  • 視覚化: d3.js, Three.js, highchart.js
  • 補助ライブラリ: moment.js, RxJS
  • 変わり種: WebRTC
バックエンド用にも型定義が多数作られている。例えば、Scala.jsをNodeJSをランタイムとして動かすのであれば、scalajs-io/nodejs は欠かせない。

型定義を書くコストをどうするか

型定義を書くのは手間だ。プロトタイピング時などは型安全を割り切って、静的型検査なしでJSを呼び出すのも一つの手だ。

Scala.js(およびScala)に備わっているDynamic型は、インスタンスのメンバー呼び出しの型検査が行われない型である。呼び出そうとしたメンバーが実際に存在すれば実行できるが、存在しなければ実行時エラーになる。このDynamic型を利用することで、まだ型定義のついていないJSライブラリを、危険ではあるがScala.jsから呼び出すことができる。

とはいえ、本格的に開発するときは、JSライブラリに型定義が欲しくなってくる。
 
しかし、JSライブラリにありがちな、奇怪なオーバーロードだらけの便利関数の挙動を調べあげ、しっかりした型定義を書くのは大変だ。ではどうするか? 

TypeScriptという巨人の肩に乗る

Scala.jsの開発者である Sebastien Doeraeneさんが、を開発し、公開されている。


TypeScriptは、Scala.jsと同じく静的型付けのaltJSだ。Microsoftが開発しており、頻繁にアップデートされている。活発なコミュニティが型定義ファイルレポジトリ DefinitelyTyped をメンテナンスしており、型定義ファイルが充実している。また近年では、JSライブラリのGithubレポジトリに、TS用の型定義ファイルが同梱されることも増えてきた。

scala-js-ts-importer を使うことで、こうしたTypeScript用の型定義資産から、Scala.js用の型定義を比較的ラクに生成できる。

ScalaとTypeScriptの型システムが完全には対応していないことから、変換は完全ではない。ただ、小一時間の手修正をすれば、実用上十分な型定義を得られる。Scala.jsを本格的に使うのであれば、scala-js-ts-importerは知っておくとよいツールだ。


scala-js-ts-importerをWebブラウザで試す

scala-js-ts-importerを使うのは、cloneして、sbtビルドして……と、一手間が必要だ。

そこで、チームメンバーらに気軽に試してもらえるようにscala-js-ts-importerのWebアプリを作った。TypeScript用の型定義ファイルを貼り付けるだけで試すことができる。

このアプリ自体、Scala.jsで書かれている。Scalaで実装されたパーサーコンビネータライブラリを使った、Scala.jsで書かれたパーサーが、Webブラウザで動いているのだ。なかなか愉快な時代である。

細かい工夫としては、巨大な型定義ファイルのパースと変換には数秒待たされることもあるので、ServiceWorkerに処理をオフロードしたりもしている(かなり雑だが)。Workerを勉強できてよかった。

scala-js-ts-importerに足りない機能を追加しまくった

scala-js-ts-importerを頻繁に使い出したら足りない機能が分かってきた。2017年のHacktoberfestのタイミングでプルリクを4つ出したらマージされた。
雰囲気でパーサーコンビネーターを使ったが、何とかなった。Hacktoberfest 2017の景品Tシャツが届くのを楽しみにしている(もう1ヶ月以上経過するがまだ来ない)。

scala-js-ts-importerハッカソンを開催した

雰囲気でパーサーコンビネーター使ってたらどうしようもなくなってきたので、助けを求めてハッカソンをやることにした。

ニッチなテーマなので、参加者ゼロで筆者1人もくもくすることを想定していたが、TwitterやNGK2017Bというイベントで雑に告知したら、予想外に4人も集まった。
  1. Scala.jsとTypeScriptに強い人
  2. Scalaとパーサーに強い人 A
  3. Scalaとパーサーに強い人 B
  4. 筆者
コーヒーや寿司の応援があり、ハッカソンでは9個のpull requestができて、全部マージされた。それぞれ得意分野があり、チームワークでもりもり進んだ感じがあって、とてもよかった。

スポンサーのご紹介

scala-js-ts-importerハッカソンでは、筆者の所属である来栖川電算に、
  • 会場
  • WiFi
  • ドリンク
  • 寿司
  • マッサージチェア
を提供いただいた。

来栖川電算は、近年はビッグデータ処理や機械学習の分野で、さまざまな企業・団体から引き合いがある。そのため、求人面では機械学習をやりたい方からの応募が多くなっているが、実は
  • 機械学習の研究者を助けるツール
  • 機械学習をお客様のビジネス(研究だけでなく実運用)で活かすSI
  • 機械学習を活かした自社製品開発
もやっていたりするので、
  • 機械学習エンジニアはもちろん、
  • フロントエンドやバックエンドに強いエンジニア
  • UI/UXに強いデザイナー、エンジニア
も求人していたりする。筆者のチームでも Scala.js、Vue、AWSなどを活用して製品開発をしているので、興味がある人は連絡いただけるとうれしい。

まとめ

人気の投稿