ごらくらいふ

プログラミングしたりゲームしたり

ふとresult.tsを更新した

Changelog

  • バージョン 0.3.0 になりました。

Enhancement

  • ok<T>(value: T) という関数を追加しました。
  • err<E>(error: E) という関数を追加しました。

Deprecated

  • Ok<T>(value: T)
  • Err<E>(error: E)

www.npmjs.com


経緯

先日、 WSL2 環境を Ubuntu 22.04 LTS に移行した。 環境が新しくなると整えたくなるもので、この移行に伴って dotfiles の整備をはじめた。

以前からなんとなく気になっていた efm-langserver を使ってみようと思い立った。 これは、 ESLint などの linter が吐き出すメッセージを Language Server Protocol (以下 LSP) に載せ替えてくれるLanguage Serverだ。 ESLint+prettierの lint結果をLSP経由で扱えるだけでも便利だし、 zenn.dev に投稿する文書を textlint で校正もできるようになる。

これの実験にちょうどよいのが result.ts だった。 ESLint , prettier, TypeScript を使っていて、ボリュームも小さいからだ。

result.ts とは

ここで一旦説明をする。 result.ts は Rust の Result を真似て書いてみたものである。

export type ResultOk<T> = {
  isError: false;
  value: T;
};
export type ResultErr<E> = {
  isError: true;
  error: E;
};

export type Result<T, E> = ResultOk<T> | ResultErr<E>;

https://github.com/yajamon/result.ts/blob/75e33b52193f5f16e99d53b43b388616ab1967b6/src/main.ts#L1-L9

  • こんな具合に、値かエラーを包んでいるオブジェクトは共通して isError を持っており、これを if でチェックするとスコープの中で型が確定できる。
  • 個人的なこだわりは、 class を使わず、ピュアなオブジェクトに包むことである。

シグネチャへの違和感

result.ts だが、最終更新を確認すると2年以上前である。 これほど時間が経つと、当時とコードに対する感覚も変わってくる。

ふとコードを見ると違和感があった。

export const Ok: <T>(value: T) => ResultOk<T> = v => ({
  isError: false,
  value: v
});
export const Err: <E>(error: E) => ResultErr<E> = e => ({
  isError: true,
  error: e
});

https://github.com/yajamon/result.ts/blob/75e33b52193f5f16e99d53b43b388616ab1967b6/src/main.ts#L13-L20

TypeScript なのに関数がパスカルケース ( Ok(v) , Err(e) ) なのだ。 当時の感覚としては、Rust の タプル構造体 を生成してるように見えて面白いからといった所だろうが、いくらなんでも寄せすぎた。

Rust においては、あくまで enum Result<T,E> のいち構造体様の生成であり、関数ではない。

doc.rust-lang.org

TypeScript / JavaScript において関数のシグネチャは、少なくともパスカルケースは主流ではない。 そしてオブジェクトの生成は new Ok(value) などとするものだ。なんとも上記のコードでは気持ち悪さを感じる。

ということで ok(v)err(e) を生やすこととした。

現行バージョンは 0.2.x だし、シグネチャをまるっと変えても良いかなと思ったけれど、「わざわざ破壊しなくてもいいか」と思いとどまった。 代わりに @deprecated アノテーションを付与した。