シェッフ、厳しい。 アンシブユはもうちょいシンプルだったけど、こちらもデバッグが厳しい。
JavaScript 祭で発表してきました
秋のJavaScript祭 in mixi で、「バグの見つけ方」について発表してきました。
過去二つのスライドをくっつけたものなので、既視感があるかもしれませんが気のせいです。
さて、前の発表を終えてから、いくつか直したかった点があったので、その点だけ修正してあります。 例えば、「ステップ実行」→「手動動作確認」のあたりですね。 ステップ実行でバグを見つけるというより、見て触っておかしいと気づいて、ステップ実行へ突入するはずですから、「手動動作確認」の方がふさわしいと思ったためです。
あと、次の2つの感想が特に嬉しかったです。ありがとうございました。
スライドめっちゃすてきだしリントやテストの大事さがすごくわかりやすい… #jsfes
— nao (@naoi109) October 15, 2016
これまでの人生で一番簡潔に型検査やリントやテストの重要性を説明されてる。パクるしかない https://t.co/1g8eAJDg6m #jsfes
— HAIL (@HAIL) October 15, 2016
HTML5 Conference 2016 の発表で自分の仕事が少しだけ紹介されていて嬉しい
TypeScript の Promise<T> が Promise<T, E> ではない理由の心当たり
TypeScript の Promise の型 だと、型パラメータが Promise#then
側しかなくて、 Promise#catch
側の型が any
になってしまって不便だ。
もし、catch
側の型についても型引数で指定できたなら、より安全なプログラミングができる。
そこで、catch
側の型を指定していない理由について考察してみた。
理想
const promise: IdealPromise<T, E> = getPromise(); promise .then((x) => { /* x は T 型 */ }); promise .catch((e) => { /* e は E 型 */ });
実際
const promise: Promise<T> = getPromise(); promise .then((x) => { /* x は T 型 */ }); promise .catch((e) => { /* e は any 型 */ });
考察
前提条件
TypeScript/JavaScript には以下の制約がある:
- 制約1: TypeScript は関数の評価時に発生しうる例外の型を検査しない
- 制約2: JavaScript はなんでも
throw
できる(例:throw null
) - 制約3:
new Promise(fn)
に与えられた関数fn
が例外e
を発生させた時、このPromise
インスタンスは理由e
で棄却状態になる
帰結
これらの制約の上でうまく型付けしようとすると、catch
側は any
にならざるをえない。
TypeScript の型検査器は、new Promise(fn)
の fn
が発生しうる例外の型を推定する材料を持っていない。
JavaScript はどんな値・オブジェクトも例外として発生させられるので、fn
から発生しうる例外の型は any
であると推論するほかない。
そして、この fn
が例外 e
を発生させたとき、この Promise は e
で棄却状態になる。
このとき、e
の型は、前述の通り any
としか推論できない。したがって、catch の引数の型は常に any である。
であれば、catch 側の型引数は必要ない。
理想に近づくためには
TypeScript に例外の型宣言ができるようになれば、できそうな気がする?
例えば:
function resolver<T, E>(resolve: (x: T) => void, reject: (e: E) => void): a throws E { // ... } const promise: Promise<T, E> = new Promise(resolver); promise .then((x) => { /* x は T 型 */ }); promise .catch((e) => { /* e は E 型 */ });
SEE ALSO
JavaScript開発における多段式エラープルーフについて
第14回HTML5ビギナーズで、JavaScript のデバッグ作業を短くする「多段式エラープルーフ」について発表してきました。
スライド
コードのサンプル
まとめ
JavaScript のデバッグ作業を素早くこなすなら、多段式エラープルーフが必要です。