JavaScriptのライブラリを徐々にTypeScriptに移行する
Alminというライブラリは元々JavaScript(+Babel)で書かれていましたが、今年の2月にsrc/
下のソースコードはTypeScriptに移行しました。
その時のコミットログは次のPRに残っているため、コミットログを1コづつ見ていけばどのように行われていったが分かると思います。
この時取った方法は大まかに次のような手順でした
src/
の TypeScript化
- Babel -> JS(js -> js)だったものをTypeScript -> Babel -> JSにビルドスクリプトを変更
- TypeScriptは
target
をesnext
にすることで単純に型を取り除くだけの変換にする - ES2015 -> ES5を実際にやるのは既存のBabelのまま
- 空のtsファイルを一つおいて実際にコンパイルが通るかを検証
- TypeScriptは
- 既存のテストを1で変換したソースで動くようにパスを変える
- 1つづつ
.js
を.ts
へ変換していく- 一時的に型が解決できないものは
any
にして後から型を直す - コンパイルが通ってテストが通るなら動作的に問題ない
- 実際に変換後のリリースではこれに起因するバグはなかったと思います
- Inroducing Almin 0.10.0: TypeScript, FlowType, Logger | Web Scratch
- 一時的に型が解決できないものは
という手順でJavaScript to TypeScriptを行いました。
この時の変更では、test/
下のテストファイルはJavaScriptのままでした。
テストの方も複雑なケースが色々増えてきたので、TypeScriptに移行したいなーと思って最近移行できる環境を作りました。
test/
のTypeScript化
src/
下はまとめて移行するスタイルでしたが、test/
下は徐々に必要なタイミングで移行できるような形にしています。
テストコードはsrc/
下とは違い、テストコード同士が互いに依存することはないため、1つのテストファイルごとに移行していけるはずです。
そのため、src/
のやり方とは異なりTypeScriptのallowJs
機能を使って移行しています。
次のPRで移行した手順が見られます(試行錯誤したのでキレイなコミットではない)
実際にまとめると次のような方法で移行しています。
test/
以下にテスト用のtsconfig.json
を追加するsrc/
用のコンパイル設定を"extends": "../tsconfig.json"
で継承し、"allowJs": true
の設定を追加したものを利用"allowJs": true
にすることで.js
もTypeScriptがコンパイルできるようになるsrc/**/*
とtest/**/*
をincludesし、テスト向けにテストコードとソースコードを一緒にコンパイルする- コンパイル結果、
src
はlib/src
へ、test/
はlib/test
へ出力する
- テストファイルが
import {Store} from "../lib/"
のソースコードをみているのを、import {Store} from "../src/"
のソースコードを見るようにする- コンパイル前は
src/*.ts
を見るが、コンパイル後はlib/src/*.js
を見ることになる - 出力先は
lib/{src,test}/
となっていて、lib/test
から../src
を見るとlib/src
をみる状態を作れる - これでコンパイル結果は全てただのJSなので、後は普通にmochaなどでJavaScriptのテストとして
lib/test
を実行する
- コンパイル前は
- テストの実行前に
test/tsconfig.json
を使ってコンパイルする"test": "npm run build:test && npm run test:js"
という感じ
test/tsconfig.json
:
{
"extends": "../tsconfig.json",
"compilerOptions": {
"allowJs": true,
"declaration": false
},
"include": [
"../src/**/*",
"./**/*"
]
}
./tsconfig.json
に"rootDir": "./",
を設定しておけば、テスト用と普段の設定で出力先が同じになる。
これで.ts
と.js
のテストファイルが混在している状態でもテストが実行できるので、必要なタイミングで.js
を.ts
に変更していけます。
alminのテスト TypeScriptに移行できる環境作ってあったけど、TypeScriptって(というかWebStormって)こんな混在してる状態でもちゃんと動くんだ
— azu (@azu_re) July 17, 2017
(TypeScript的にはAllowJSしてる、WebStorm普通に補完効いてて面白い) pic.twitter.com/OUBcmOYjZv
またすべてのテストがTypeScriptにはなってないのでコントリビュート待ってます。
基本的には.ts
にして型エラーを潰していくだけの作業だと思います。
すべてのテストが.ts
になった後は、ts-node/registerなどを使ってruntime hookで変換できるのでnpm run build:test
が必要なくなります。
おわり
src/
のように依存関係があるものは一気にTypeScriptへ変換した方が良いです。
一方、test/
のようにそれぞれのファイルが独立しているものは、--allowJs
を使うことで既存のJavaScriptを混ぜた状態でTypeScriptへ移行できるようになりました。
最近だと--checkJs
と--allowJs
を使うことでJavaScriptファイルに対してJSDocを使ったType Checkができるようになっています。
これを上手く使えば、もっと緩やかに移行することができるかもしれません(JSDoc全部のパターン対応してないので今の所限定的)
- TypeScript 2.3: Type-Checking JavaScript Files with –checkJs | Marius Schulz
- Type Checking JavaScript Files · Microsoft/TypeScript Wiki
今回はライブラリだったので、テストカバレッジがかなり高い状態でした。 なのでテストがある程度保証してくれるので、一気にやっても壊れにくい状態でした。
UIなどテストがしにくい部分を含む実際のアプリケーションに後から型付けしていく場合は、次の記事などが参考になるかもしれません。
お知らせ欄
JavaScript Primerの書籍版がAmazonで購入できます。
JavaScriptに関する最新情報は週一でJSer.infoを更新しています。
GitHub Sponsorsでの支援を募集しています。