🙅‍♂️

[失敗] Promise.allを順序じゃなく「意味」で束ねた ― keyedPromiseAll

に公開

経緯

Promise.all って、タプルの順序が変わらないことを前提に作られていて
それ自体は言語仕様だし悪いことじゃないんだけど、自分にとってはちょっと気持ち悪かった。

なので、順序ではなく、処理に意味(key)を持たせて応答と紐づける仕組みを作ってみた。

仕組みの話

全体の構成としては

namespace keyedPromiseAll
  promiseAll ... Promise配列を受け取って、待ってから返す
  promiseAllWithArgs ... 関数と引数の配列を受け取って、待ってから返す

この2種類を作成した。

なるべく型安全に作ったのだけど、どうしてもPromise<any>を消しきれない部分
(正確には、L69 の fn が、どんなに頑張っても関数定義のTの制約に引きづられる)
があるので、完成かと言うとちょっと微妙なのだけど、仕組みで整合性は確保してる。

一部簡単なUtilityも付け加えたけど、もう少し使いやすくする予定で、
それは別枠で扱おうかなと思っている

コード

https://github.com/risk/ts-playground/blob/main/src/keyedPromiseAll/keyedPromiseAll.ts

扱う型の定義

https://github.com/risk/ts-playground/blob/86df52d5335d32e7297adcdfce6d10c15c9ccbf9/src/keyedPromiseAll/keyedPromiseAll.ts#L8-L34
全体てみるともう少し、関数内の定義もあるけど、おおよそはここに集約。
引数に渡された構造から、keyの構造を崩さずに、いろんな箇所の型を抜き出すことをしてる。
「抜き出してる!」って感じがする代表格は ArgsMap かなぁ。
関数が引数で渡ってくるので、そのパラメータを引き出す感じ。

ちなみに、タプルのKeyを崩さずに、異る型に違う抜き出しを書けるみたいな書き方は、わからかったので、ChatGPTに聞いたら、「こうするとできるぞ」って一瞬で出してきて、悩んだ俺がアホみたいだw
知らないことがまだまだ多すぎるね。

PromiseAll

Promise配列をうけとって待ってくれる、元の Promise.all に似た動き
https://github.com/risk/ts-playground/blob/86df52d5335d32e7297adcdfce6d10c15c9ccbf9/src/keyedPromiseAll/keyedPromiseAll.ts#L36-L63
処理的には、受け取ったPromiseの配列をPromiseAllでまたせるんだけど、このときに
Keyの部分を崩さないように処理してる。
結果を書き戻すときに、Keyを基準にいれていくことで、それぞれの結果がそれぞれの名前で保持される。成功失敗に関しては、Promiseの単位でみていて、rejectされた場合とかは、okがfalseになって、errorがセットされる仕組み

PromiseAllWithArg

関数と引数の配列をうけとって、中で実行までしてくれる PromiseAll
https://github.com/risk/ts-playground/blob/86df52d5335d32e7297adcdfce6d10c15c9ccbf9/src/keyedPromiseAll/keyedPromiseAll.ts#L65-L96
受け取った内容の実行をかけてから、Promiseの結果を集めて返してくれる仕組みです。

handleResult

https://github.com/risk/ts-playground/blob/86df52d5335d32e7297adcdfce6d10c15c9ccbf9/src/keyedPromiseAll/keyedPromiseAll.ts#L98-L104
結果がだいぶ見づらいので、ヘルパー関数を用意してみました

実行部分

https://github.com/risk/ts-playground/blob/86df52d5335d32e7297adcdfce6d10c15c9ccbf9/src/keyedPromiseAll/keyedPromiseAll.ts#L106-L179
ここからは実行部分です。
関数をタプルに詰め込んで送り込むと、結果が返却されてきます。

Discussion