若くない何かの悩み

何かをdisっているときは、たいていツンデレですので大目に見てやってください。

JavaScript 祭で発表してきました

秋のJavaScript祭 in mixi で、「バグの見つけ方」について発表してきました。

speakerdeck.com

過去二つのスライドをくっつけたものなので、既視感があるかもしれませんが気のせいです。

さて、前の発表を終えてから、いくつか直したかった点があったので、その点だけ修正してあります。 例えば、「ステップ実行」→「手動動作確認」のあたりですね。 ステップ実行でバグを見つけるというより、見て触っておかしいと気づいて、ステップ実行へ突入するはずですから、「手動動作確認」の方がふさわしいと思ったためです。

あと、次の2つの感想が特に嬉しかったです。ありがとうございました。

HTML5 Conference 2016 の発表で自分の仕事が少しだけ紹介されていて嬉しい

HTML5 Conference 2015 の @dynamis さんの発表で、過去の闇祓い業に触れられていました。

dynamis さんの発表

28ページ目でちょろっと触れられています。

闇祓い業

alpha.mixi.co.jp

まとめ

うれしい 😊

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

github.com github.com github.com