JavaScript のパーサコンビネータに TypeScript で型を付けた

こんにちは, 口の中パッサパサです.


さてパッサパサといえばパーサコンビネータの話をしましょう.

以前作った JavaScript 用パーサコンビネータライブラリ の TypeScript 向けインターフェースをつくりました.

github.com

こんな感じで使えます. どーしてくれんだマリコちゃん.

import { string, StringParser } from "typed-loquat";

const p = string();
type P<T> = StringParser<T>;

const parser: P<string> = p.string("口の中").and(
    p.anyChar.manyTill(p.string("だよ").try()).map(cs => cs.join("")).bind(term =>
        p.string(term).and(p.eof).return(term)
    )
);

const result = parser.parse("", "口の中パッサパサだよパッサパサ");
if (result.success) {
    console.log(result.value); // → パッサパサ
}

まあこれは冗談として, サンプルいくつか用意してるのでこちらを見てください.

まだ型付けてみたって感じの alpha 版なので, なんか型付けミスってるとか使いにくいとかあればフィードバックください.

特徴

なんで @types/loquat とかでないのか

元の JS のライブラリの方を見てもらえるとわかると思うのですが, インターフェースが型を付けるのに恐ろしく適していないです. 大体全部 bind operator とか pipeline operator みたいなのが無いために prototype 拡張で凌いでいるのが悪い. これは当初から認識していて, まあいざ型提供したくなったら適当に固めたパッケージ作って提供してやればよかろうと思っていて, 今回のがそれです.

TypeScript について

だいたい Flow は触るたびにげんなりして帰ってくる*1って感じだけど, TypeScript はあんまりそういうことはなくて良いです.

*1:existential quantification すると壊れるとか (修正済み), interface の型引数に variance つけると壊れるとか (たぶんまだ修正されていない), existential types とか module types とかの命名に色々なものへのリスペクトを感じられないところとか