1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Next.js + サーバーサイドTypeScript + 関数フレーバーでクリーンなアプリを作ったので実装意図とか書く Advent Calendar 2022
8日目株式会社mofmofに生息しているshwldです。

前日はEither型について書きました

TaskEither型を使ってResult型を作る

fp-tsにはTaskEitherというものがあります。
失敗する可能性のある(Either)非同期処理(Task)を表現することができるものです。

具体的にみていきましょう。

fp-tsのtryCatchを使うことで、PromiseをTaskEitherに変換することができます。

import { tryCatch } from 'fp-ts/TaskEither'

const taskEither = tryCatch(() => {
  saveToDatabase()
}, e => {
  if (e instanceof PrismaClientRustPanicError) {
    return new OriginalDBError(e);
  }
  return new OriginalRuntimeError('error');
}

上記で得られる taskEither は実行(taskEither())するとPromise<Either<left, right>>が返ってきます。

嬉しいこと

Eitherの利点については昨日書いたので、ここではTaskの利点について説明します。
Taskを使うことで、複数のPromiseの直列実行、並列実行を操作し一つのPromiseにまとめて、Eitherの配列にしてくれます。

import { sequenceArray } from 'fp-ts/TaskEither'

const taskEithers = items.map(item => saveToDatabase);
// taskEithers is TaskEither<OriginalDBError, DBResult>[]
const taskEither = sequenceArray(taskEithers)
// taskEither is TaskEither<OriginalDBError, DBResult[]>
const results = await taskEither()
// results is Either<OriginalDBError, DBResult[]>

一つのPromiseにまとめてくれることにより、取り出す際に一つ一つawaitしたりすることがなくなるのはもちろん、取り出す以前の状態で、直列、並列実行を指定でき、宣言的に非同期処理を扱えて嬉しい。

EitherとTaskEitherを区別するのがだるい

EitherとTaskEitherを使えるようになりました。
fp-tsには他にもOptionやIOなど連続した処理の流れの中で例外を管理するような仕組みがいくつもあります。

TaskEitherをResult型として使う

今回自分のテーマとして、関数型を知らない人でも書けるといいなと言う思いがありました。
そこで、選択したのがResult型として、TaskEitherのみを使うという選択です。

EitherをすべてTaskEitherに変換することで、すべての処理の連続の中でResult型だけを気にすれば良くなりました(これがいいのかはわかりませんが)
つまり、すべてPromiseとして扱うということになり、そこは少し抵抗があったのですが、同期でないとやりづらいところはsuffixにSyncをつけたバージョンのメソッドを生やすようにしました。

コードをみるとわかりますが、Result型はいたるところに出てきます。

/domain/core/src/models/account/mutations/build-account.ts
export const build = (
  input: Account_BuildInput
): Result<InvalidAttributesError, Account_BuiltAttributes> => {
  return pipe(
    {
      ...input,
      createdAt: new Date(),
      updatedAt: new Date(),
    },
    validateWith(validationSchema),
    map(v => ({
      ...v,
      __state: STATE_IS_BUILT,
    }))
  );
};

https://github.com/shwld/uzumaki/blob/main/domain/core/src/models/account/mutations/build-account.ts#L39

次回予告

明日はエンティティの状態遷移関数について書きます。

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?