🐳

Result型のライブラリを作りました【TypeScript】

2023/08/30に公開

Rust, Kotlin, Swiftなどのモダンな言語ではいわゆるResult型が標準で提供されていますがTypeScriptにはありません。
なので既に何人もの開発者がResult型のnpmパッケージを公開しているのですが、自分好みのものが見当たらなかったので自作しました。

設計上の工夫

TypeScriptでは型と同名の名前空間を両立して定義できます。
この仕様を使って型(export type Result)と名前空間(export namespace Result)の両方を定義し、ヘルパー関数などは全て名前空間の中に配置しました。
そのおかげでResultだけをimportすれば済みますし、関数名などを覚えていなくてもエディターの候補表示から全てのユーティリティを辿れるようになっています。

こういう設計にするとTree shakingが効かなくなってしまうのですが、Result型だけの小さなライブラリなので普通のプロジェクトではバンドルサイズはほとんど誤差になってメリットの方が上回るのではないかと考えました。

使い方

https://www.npmjs.com/package/result-type-ts
↑のnpmパッケージをインストールして、以下のような感じで使えます。

import { Result } from 'result-type-ts'

const result = Math.random() < 0.5 ? Result.success(123) : Result.failure('error')

// 条件分岐しなくても内部の値を取得できます
console.log(result.value) // 123 または undefined
console.log(result.error) // undefined または 'error'

if (result.isSuccess) {
  // result.valueの型はnumber | undefinedからnumberにナローイングされます
  console.log(result.value)
} else {
  // 同じくresult.errorはstring型にナローイングされます
  console.log(result.error)
}

幅広いユースケースに対応するため、Result関連のユーティリティをたくさん収録してあります。
この記事は単なる紹介記事なので、関数などの名前の一覧だけ掲載しておきます。
ちゃんとしたドキュメントはREADME内にあります。

関数

  • Result.success(value)
  • Result.failure(error)
  • Result.tryCatch(f)
  • Result.fromNullish(value)
  • Result.fromPromise(promise)
  • Result.all(results)

  • Result.Success<T>
  • Result.Failure<E>
  • Result<T, E>

プロパティ

  • result.value
  • result.error
  • result.isSuccess
  • result.isFailure

メソッド

  • result.getOrThrow()
  • result.toUnion()
  • result.ifSuccess(f)
  • result.ifFailure(f)
  • result.match(f, g)
  • result.map(f)
  • result.mapError(f)
  • result.flatMap(f)
  • result.flatten()
  • result.assertErrorInstanceOf(constructor)

以上です!
もしかしたらEither型のライブラリも作るかもしれません(ほとんど同じ内容なので…)。

chot Inc. tech blog

Discussion