TypeScript の fp-ts の Option を使って例外処理をなくしてみた

以下の処理を考えます。

  1. ユーザーデータから、指定したIDを持つユーザーを取得
  2. ユーザーから年齢を取得
  3. 年齢から 100 / (age – 10) の値を取得
  4. 3が80を超えていたら、OKを返す。それ以外はKOを返す

この処理の中にはいくつか例外処理を入れる必要があります。

  • ユーザーが見つからなかった場合
  • 年齢が10以下だった場合

これらの例外処理を途中でせずに、最後の4のステップで判定します。

以下コードです。

import * as O from 'fp-ts/Option'
import { findFirst } from "fp-ts/lib/Array"
import { pipe } from 'fp-ts/lib/function'

type User = {
    id: number
    name: string
    age: number
}

const users: User[] = [
    {
        id: 1,
        name: 'hoge',
        age: 10,
    },
    {
        id: 2,
        name: 'foo',
        age: 20,
    },
    {
        id: 3,
        name: 'bar',
        age: 80,
    },
    {
        id: 4,
        name: 'bar',
        age: 11,
    },
    {
        id: 5,
        name: 'bar',
        age: 9,
    },
]

const eqId = (id: number) => (user: User) => user.id === id
const getAge = (user: User) => user.age
const calcNumFromAge = (age: number) => 100 / (age - 10)
const isTarget = (num: number) => num > 80

// これは pipe を使わないバージョン
// const main = (userId: number) => {
//     const user = findFirst(eqId(userId))(users)
//     const age = O.map(getAge)(user)
//     const calculatedNum = O.chain((num: number) => {
//         return num <= 10 ? O.none : O.some(calcNumFromAge(num))
//     })(age)
//     const target = O.filter(isTarget)(calculatedNum)
//     return O.fold(() => 'ko', () => 'ok')(target)
// }

const main = (userId: number) => {
    return pipe(
        findFirst(eqId(userId))(users),
        O.map(getAge),
        O.chain((num: number) => {
            return num <= 10 ? O.none : O.some(calcNumFromAge(num))
        }),
        O.filter(isTarget),
        O.fold(() => 'ko', () => 'ok'),
    )
}

console.log(main(0)) // userがみつからないのでko
console.log(main(1)) // age <= 10 をみたすのでko
console.log(main(2)) // calculatedNum が 10 なので ko
console.log(main(4)) // ok
console.log(main(5)) // age <= 10 をみたすのでko
console.log(main(100)) // userがみつからないのでko

例外をなくせるし、pipe で見やすくなるが、関数型プログラミングがそこまで一般的ではないので、チーム開発には向いていない印象でした。