いろいろ試した結果
effect-tsのような書き方を排除する書き方を採用したくなった
基本的に使うのは以下のみぐらいがいい気がする
- Effect.succeed
- Effect.fail
- Effect.gen(function*() { ... })
- Effect.either( ... )
成功と失敗が2つある関数の場合
普通に成功時の値と失敗時の値を変数で用意して、最後にEffect.succeedかEffect.failで返す
const InputData = Schema.Struct({
route: Schema.Tuple(Schema.Number, Schema.Number)
})
type InputDataType = typeof InputData.Type
// ---- 料金計算 ----
function routeFareCalculation(input: InputDataType) {
const [start, end] = input.route
if (start === end) {
const ng_result = "開始位置と終了位置が同じです"
return Effect.fail(ng_result)
} else {
const ok_result = Math.abs(start - end)
return Effect.succeed(ok_result)
}
}
成功の場合のみを扱う後続の関数
Either型を外部に出さないで成功した時にデータとして表現したい形のみを使用する
// ---- OKデータ処理 ----
const RouteAndFareData = Schema.Struct({
route: Schema.Tuple(Schema.Number, Schema.Number),
fare: Schema.Number
})
type RouteAndFareDataType = typeof RouteAndFareData.Type
function displayRouteAndFare(routeAndFare: RouteAndFareDataType) {
const [start, end] = routeAndFare.route
console.log(`start: ${start}, end: ${end}, fare: ${routeAndFare.fare}`)
}
失敗の場合のみを扱う後続の関数
Either型を外部に出さないで失敗した時にデータとして表現したい形のみを使用する
// ---- NGデータ処理 ----
type ErrorMessage = string
function displayError(error: ErrorMessage) {
console.log(`error: ${error}`)
}
全体
programでそれぞれの関数の結果をEither型で取得したり、後続用のデータを作成したりする
こういうつなぎのための関数が1つは必要で、そこでEffect.gen(function*() { ... }) を使う
Effect.either( ... ) で成功か失敗かの値を取得する
全ソース
import { Effect, Either, Schema } from "effect"
const InputData = Schema.Struct({
route: Schema.Tuple(Schema.Number, Schema.Number)
})
type InputDataType = typeof InputData.Type
// ---- 料金計算 ----
function routeFareCalculation(input: InputDataType) {
const [start, end] = input.route
if (start === end) {
const ng_result = "開始位置と終了位置が同じです"
return Effect.fail(ng_result)
} else {
const ok_result = Math.abs(start - end)
return Effect.succeed(ok_result)
}
}
// ---- OKデータ処理 ----
const RouteAndFareData = Schema.Struct({
route: Schema.Tuple(Schema.Number, Schema.Number),
fare: Schema.Number
})
type RouteAndFareDataType = typeof RouteAndFareData.Type
function displayRouteAndFare(routeAndFare: RouteAndFareDataType) {
const [start, end] = routeAndFare.route
console.log(`start: ${start}, end: ${end}, fare: ${routeAndFare.fare}`)
}
// ---- NGデータ処理 ----
type ErrorMessage = string
function displayError(error: ErrorMessage) {
console.log(`error: ${error}`)
}
const program = Effect.gen(function*() {
const input = InputData.make({ route: [123, 456] }) // ok
// const input = InputData.make({ route: [456, 123] }) // ok
// const input = InputData.make({ route: [111, 111] }) // ng
const result = yield* Effect.either(routeFareCalculation(input))
if (Either.isRight(result)) {
const ok_result = result.right
const routeAndFare = RouteAndFareData.make({
route: input.route,
fare: ok_result
})
displayRouteAndFare(routeAndFare)
} else {
const ng_result = result.left
displayError(ng_result)
}
})
Effect.runSync(program)