tsでmatch式をメソッドチェーンではなくモジュラーに実装したい
この実装自体は良い
しかし、メソッドチェーンというのは、実装の読みやすさ、メンテナビリティがやや低い
zodに対するvalibotのような実装を試してみたい
code:ts
match(value)
.when(pred => (v) => v * 20)
.when(pred => (v) => v * 20)
こうではなく
code:ts
match(value)([
when(pred => (v) => v * 20),
when(pred => (v) => v * 20),
])
このような感じで、whenが単一の関数であり、配列でまとめられるようにしたい
match側のインターフェースは細かい検討は必要
ランタイム側の実装は簡単で、難しいのは型安全性を手に入れるための型パズル 無理かと思ってたが、なんとか分かってきた
やってる最中で学んだこと
適切にgenericsを効かせて型推論を動かすためには、型引数を適切によしなにやる必要がある
で、TSだと型引数を直後で使ったり、名前をつけたりするのがむずい
なので、
高階関数で本体を書いておいて、
境界はいい感じの引数にしつつ、
最低限で確実に正しい型の強制だけをするとよい
途中
https://gyazo.com/027e355618b0ca697e0c06b64d6a8e74
whenってのは一つのMatcherという型で、複数のMatcherを合体して、1つのMatcherを作ってる
code:ts
if(a) then AA
if(b) then BB
この2つを合体させると、
コードとしてはこうなのだが、
code:ts
if(a) return AA
else if(b) return BB
型としてはこうなる
code:ts
if( a or b) then AA or BB
これを型レベルで行っている
欲を言うと、こうなってるのだから
1 -> 100
2 -> 200
3 -> 300
inputが1のときに中身が100であることは確定させたい
でも現状の型レベルの実装はそれができないなあ
ただ、そもそも、入力が型レベルで分かっているなら、パターンマッチをするはずがない、と考えられるので、この対応は実用性のアドバンテージがほぼ無いので、無視しても良いかもしれない
いや、実装方法は思いつくな
input, outputのtupleのarrayとしてreduceして、Iと&でinputをfilterして、neverでなければ対応するoutをunionすればいい
できた
code:ts
const result = match(v,
//^?
when(is(1), (v) => 100 as const),
when(is(2), (v) => 200 as const),
when(is(3), (v) => 666600 as const),
reduceMatchers(
when(is('a'), (v) => 'aaa' as const),
when(is('b'), (v) => 'bbb' as const),
when(is('c'), (v) => 'ccc' as const),
)
)
こういうのも対応したくなってきたな
型レベルでflatすれば良いんだが
Matcherを配列にしようとして、見づらいからよくない
MatcherとMatchersは型として分けたほうがuser側のreadabilityも高い
flatむずい
https://gyazo.com/3a8897eaea0bb8338bb14fa561cd774e