まえがき
-
DefinitelyTyped
とは、言わずと知れた TypeScript 用の型定義リポジトリ。 - 昨今、特にフロントエンドでは TypeScript を使うのが当たり前となったが、まだまだ過去の遺産、型定義すらない JavaScript ライブラリも多い。
- 型定義がなければ自前で書く必要があり、せっかく書いたのなら公開して、世界のどこかで悲しむ誰かを救いたい。
- 「型定義を書く」とは、基本的に公式ドキュメントを TypeScript に変換することである。
- つまり、基本的な TypeScript の知識と根性さえあれば書くことができる。
- なので、「とりあえず OSS コントリビューターとしての実績作りしたい」みたいな下心を満たすのにも
DefinitelyTyped
は打ってつけなのである。
以下、先人達のナレッジ + 自分用に整理した 型定義を新規追加する場合の 手順を書き残す。
環境
- macOS: 10.12
- CPU: 1.8 GHz
- Mem: 8 GB
- node: v13.12.0
- npm: 6.14.4
- 対象 package: jexcel (*)
(*) jexcel とは
- 非常に高機能な Excel ライクな表入力ライブラリ。
- 正直これが無料はちょっと引くレベル(褒め言葉)なので、ぜひ 1 度触ってみてほしい。
- 以下、jexcel + TypeScript + React のサンプル。
準備
- GitHub 上で DefinitelyTyped のリポジトリを Folk する。
- 以下の手順で、ローカルに環境構築する
(手順中の具体的な数字 (size など) は、2020-04-12 時点のもの。参考まで。)
# git clone。約 15 分で完了。
$ git clone git clone https://github.com/${MY_NAME}/DefinitelyTyped.git
# > Receiving objects: 100% (486652/486652), 542.02 MiB | 683.00 KiB/s, done.
# いつもの
$ npm i
# 何はともあれ test を試す。6681 packages の test が実行される。約 3 分で完了。
$ npm t
# 何はともあれ lint を試す。`For a good example package, see base64-js.` とのことなので。
$ npm run lint base64-js
# 型定義のベースを作成する。`For a good example package, see base64-js.` とのことなので。(*1)
$ cp -r types/base64-js types/jexcel
$ mv types/jexcel/base64-js-tests.ts types/jexcel/jexcel-tests.ts
# 後はお好みのエディタで。
$ code .
(*1) 型定義のベースの作成方法について
- 基本的には『「dts-gen」を使って型定義の雛形を生成せよ』とプルリクテンプレートに書かれている。
- しかし、dts-gen は「Browser support in progress! This is not quite ready yet.」
- つまり、ブラウザ JavaScript 実行環境特有の値 (
document
など) を使う package には非対応である。- jexcel はこれに該当するため、雛形は上記手順の通り cp で作成した。
雛形の書き換え
$ diff -r types/base64-js types/jexcel
Only in types/base64-js: base64-js-tests.ts
diff -r types/base64-js/index.d.ts types/jexcel/index.d.ts
1,3c1,3
< // Type definitions for base64-js 1.2
< // Project: https://github.com/beatgammit/base64-js
< // Definitions by: Peter Safranek <https://github.com/pe8ter>
---
> // Type definitions for jexcel 3.9
> // Project: https://github.com/paulhodel/jexcel
> // Definitions by: arx-8 <https://github.com/arx-8>
Only in types/jexcel: jexcel-tests.ts
diff -r types/base64-js/tsconfig.json types/jexcel/tsconfig.json
5c5,6
< "es6"
---
> "es6",
> "dom"
21c22
< "base64-js-tests.ts"
---
> "jexcel-tests.ts"
- tsconfig.json
- 今回の package では DOM 特有の型 (
HTMLElement
型など) が登場するため、compilerOptions.lib
に"dom"
を追加した。
- 今回の package では DOM 特有の型 (
型定義を書く
- 型定義を書く。
- 型なき世界への怒りと悲しみを燃やして、根性で書く。
- 公式のドキュメントを参照したり、
console.log(typeof value)
やconsole.log(value.constructor)
を駆使して、闇を切り開く。
ツール
- 以下の 2 コマンドをエラーがなくなるまで叩く&修正。
# lint
npm run lint jexcel
# formatter
npm run prettier -- --write types/jexcel/**/*.ts
lint の rule の無効化について
- 特にレガシーな package の場合、そう簡単に全ての型定義を書かせてくれないことが多い。
- 例えば、デフォルトでは
ban-types
でFunction
型がエラーになる。- もちろん極力修正したいが、時間的制約などで全て対応できないこともある。
- 「とりあえず関数なのはわかるが、正確なシグネチャがわからない」場合に
Function
型を使いたい。 - そのような場合は、
// tslint:disable-next-line ban-types
のラインコメントによる disable が推奨らしい。-
tslint.json
should be present and it shouldn't have any additional or disabling of rules. Just content as{ "extends": "dtslint/dt.json" }
. If for reason the some rule need to be disabled, disable it for that line using// tslint:disable-next-line [ruleName]
and not for whole package so that the need for disabling can be reviewed.
-
- 完璧な定義より、まずは全体像の把握・本当に必要な定義の完成を目指した方が、コスパがよいと思う。きっと Done is better than perfect.
サンプルコードを書く
- 型定義が正しいこと・予期せぬ型エラーがないことを示すため、ファイル名
${PACKAGE_NAME}-tests.ts
にサンプルコードを書く - このコードは、実際に処理が実行されるものではない。
- ただ型チェックのみが実行される。
- 公式のサンプルコードをコピペ・足りない型宣言を追記する等で、なるべくカバレッジを高めておく。
型定義の動作確認
UnitTest
npm t
自分で使ってみる
- もしその package を使用しているプロジェクトがあるなら、型定義を実際に使ってみる。
- プロジェクトの
node_modules/@types/
配下にindex.d.ts
ファイルを置けば、npm i @types/*
した時と同じように動作する。- 例えば、今回は
${MY_PROJECT}/node_modules/@types/jexcel/index.d.ts
に定義を置いて、動作確認した。
- 例えば、今回は
プルリクエスト
作成
- 「Make a pull request」の手順に従う。
- Folk した自分の DefinitelyTyped のリポジトリに、プルリクエストを作成する。
- プルリクエストテンプレートのチェックリストを埋める。
- merge の from/to を確認する。
- from: 自分の型定義追加・修正ブランチ
- to: DefinitelyTyped/DefinitelyTyped リポジトリの master ブランチ
- 「Create pull request」
これで作業完了。お疲れさまでした。
以下、実際に作成したプルリク。
(ミス・拙い英語・時間都合で省いた定義、諸々恥ずかしいレベルだが、自戒も込めて晒しておく)
https://github.com/DefinitelyTyped/DefinitelyTyped/pull/43837
プルリク作成後の時系列
- 基本、プルリク作成で作業完了である。
- もちろんレビュー指摘があった場合は、状況に応じて対応が必要。
- ただし結構待ちがあり、何か手順見落としたのではとハラハラした。
- 参考までに、今回の時系列を書いておく。
2020-04-12 20:25 JST: プルリク作成
2020-04-12 21:22 JST: typescript-bot がやってきて、コメントと適切なラベルを付与
2020-04-14 08:12 JST: レビュー指摘 (1 回目) を頂く
2020-04-15 07:31 JST: レビュー指摘 (1 回目) の反映を push
2020-04-18 05:38 JST: レビュー指摘 (2 回目) を頂く(すまぬ・・・すまぬ・・・)
2020-04-18 14:22 JST: レビュー指摘 (2 回目) の反映を push
2020-04-21 06:26 JST: merged
2020-04-22 05:54 JST: typescript-bot がやってきて、npm に publish
- 計 10 日掛かった。
- 1 発で通れば 3 日、レビュー 1 回で通れば 6 日くらいか。
その他ナレッジ
参考プルリクエスト探しには、GitHub label を使う
- 例えば、「型定義の新規追加のプルリクエスト」を探したい場合は、ラベル「New Definition」を見てみる。
感想
- DefinitelyTyped、巨大なリポジトリなので「git clone や vscode で開いたりしたら PC がぶっ壊れるんじゃないか」なんて謎の先入観を持っていたが、全く無問題だった。 git と vscode は偉大。
- 英語は、読む。
- 諦めて、根性で読むしかない。Google翻訳・DeepL翻訳を駆使して、公式は読む。
- 変に日本語訳や噛み砕いた(古い)情報を探しても「最新版は違っていた」なんてこともある。(じゃあこの記事も書くなよという話ではあるが)
- もちろん、雰囲気を知るため簡単な日本語記事から読み始めるのはアリ。しかし、最後はやはり「公式を読め」。
- 型安全な世界を目指して、今後ともぜひ TypeScript & DefinitelyTyped やっていきましょう。