🧮

手もとに計算機がないけどTS型だけあるとき

に公開

「困った、計算機がない、TSの型を見られる環境だけならあるのに」

みなさん、そんな経験、一度はありますよね。

そんなあなたに、TSの型だけで計算する方法です。

四則演算のコードはこちら

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

最初に

そもそもコレをやった理由は、自分の「infer」と「extends」の理解が足りなかったからです。
この2つは、TSで型を扱う上で、避けて通れないもので、ちょっと小難しいことをしようとすると、必ずでてきちゃいますが、理解が難しい部類だと思っています。
extendsとinferに関しては、別途書こうかと思います(サンプルだけはこちらに書きました)

数値の扱い方(基礎)

数字はタプルの個数で扱います。
型の中で演算はできないので(できないよね?)タプルの個数を数字に見立てて、最後に配列の長さを数字のリテラルに変換する方法を取ります。
https://github.com/risk/ts-playground/blob/86df52d5335d32e7297adcdfce6d10c15c9ccbf9/src/typeCalc/typeCalc.ts#L7-L9
数字を渡すと、その個数のタプルを作ってくれる Value です。
Value は T に数字(リテラル)を渡すと、その数字をAの個数と比較します。
同じ個数であれば、Aを返し、違う個数であれば Aの配列に一つ要素を足して、再度Valueを呼びます
コレを繰り返していくと、出来上がる型は、数字の個数分のタプルになるわけです。

逆に数字から戻すときは、その配列の個数を取得します(Valueのところでもやってますが)
https://github.com/risk/ts-playground/blob/86df52d5335d32e7297adcdfce6d10c15c9ccbf9/src/typeCalc/typeCalc.ts#L11-L18
渡したタプルの個数を取得すれば、数字リテラル型になります。

加算

https://github.com/risk/ts-playground/blob/86df52d5335d32e7297adcdfce6d10c15c9ccbf9/src/typeCalc/typeCalc.ts#L20-L23
これは、タプル型を合成しているだけなので、割とわかりやすい

減算

こいつは、作ってる途中にあれっとおもって2パターンでてきました。

ver.1

1個ずつ要素を削っていき、なくなるまで続ける方法
https://github.com/risk/ts-playground/blob/86df52d5335d32e7297adcdfce6d10c15c9ccbf9/src/typeCalc/typeCalc.ts#L25-L30
lessOneは、要素を一つ減らす仕組みです。
これを使って、一つづつ減らしながら T2が0個になるまで続けることで T1の残りが減算の結果になります。

ver.2

割り算しようとして気がついたんですが、そもそも、一気に減らしてしまえばよかった。
https://github.com/risk/ts-playground/blob/86df52d5335d32e7297adcdfce6d10c15c9ccbf9/src/typeCalc/typeCalc.ts#L38-L42
T1のタプルを T2とその他の形でマッチしてあげて、その他の部分を抜き出せば減算になります。

乗算

小学生の頃にやった説明をそのままやった感じですね。
https://github.com/risk/ts-playground/blob/86df52d5335d32e7297adcdfce6d10c15c9ccbf9/src/typeCalc/typeCalc.ts#L32-L36
T2を減らしながら、T1を足し続けます。
結果はNextに入れておき、最後にT2が0個になった時点で、NEXTを返せば乗算になります。

除算(と、余り)

除算に関してはだいぶ迷いましたが、引けない状態まで持っていくイメージで作っています。
https://github.com/risk/ts-playground/blob/86df52d5335d32e7297adcdfce6d10c15c9ccbf9/src/typeCalc/typeCalc.ts#L44-L52
T1の型がT2の型を充足していない = マッチできない という状態をつくって、掛け算の用に引いていきます。回数を記録しておけば、除算の結果、残ったタプルの個数が余りになるわけです。

終わりに

きっともっといい方法がいっぱいあるんだろうなと思いますが、そもそも再帰数の限界等あるそうなので余り大きい数字には使えないそうです。(あとからAIさんが教えてくれた)
最初の数字の扱いに気がつけば、意外と行ける感じもしますが、コレをやるために
嫌でも extends と infer に触れまくることになるので、この2つを使いたいなぁと感じる方は、お試しいただくと面白いかと思います。

ちなみに、私がコレをやろうと思ったきっかけは、ChatGPTに
「配列(まだタプルと配列の区別がついてない)の個数って、型の段階で取れるの?」
と聞いたことがきっかけでした。
ぐぐってみると、やっぱりやってる人は結構居て、狂ってる(褒め言葉)とおもいました。
ついでに色々聞いてると、なんか型の世界の「通過儀礼」みたいなもんらしいですね。
色々と恐怖を感じます(笑)

Discussion