📝

TypeScriptでResult<T>を実装

2021/06/21に公開1

すでに存在していたら教えてください


2021.06.21追記
少しシンプルになりました
🙌 https://twitter.com/SubaruG/status/1406869743894634496?s=20


要件

  • TSCがTの型チェックをしてくれること
  • succeededの場合はT, failedの場合はErrorのメンバにアクセスできること

実装

export type ResultType<T> = ResultSucceeded<T> | ResultFailed

export class ResultSucceeded<T> {
  public readonly resultType = "succeeded"

  public constructor(public readonly value: T) { }
}

export class ResultFailed<T> {
  public readonly resultType = "failed"

  public constructor(public readonly error: Error) { }
}

使用

function someTest(arg: string): ResultType<string> {
  if (arg.length > 0) {
    return new ResultSucceeded("ok")
  } else {
    return new ResultFailed(new Error("Empty argument"))
  }
}

const result = someTest("...")
switch (result.resultType) {
case "suceeded":
  console.log(`Succeeded! ${result.value}`)
  break
  
case "failed":
  console.log(`Failed (T.T) ${result.error}`)
  break
}

Discussion

nap5nap5

すでに存在していたら教えてください

このトピックfunctional-programmingからなら、いろいろ見つかるかと思います。

https://github.com/topics/functional-programming?l=typescript

neverthrowライブラリから提供されているResult型を使ってデモ作ってみました。

https://codesandbox.io/p/sandbox/young-sky-owe2p2?file=%2FREADME.md

const handler = nextConnect<NextApiRequest, NextApiResponse>().get(
  async (req, res) => {
    const mockError = <T>() =>
      Result.fromThrowable(
        (d: T) => {
          if (isRandomError()) {
            dispatchCustomServerSideError()
          }
          if (isRandomError()) {
            dispatchInvalidArgumentError()
          }
          return d
        },
        (e) => {
          return e as ErrorData
        }
      )
    const doThrowable = mockError<UsersData>()
    doThrowable([
      { id: 1, name: 'Spike', age: 29 },
      { id: 2, name: 'Fei', age: 30 },
      { id: 3, name: 'Edo', age: 13 },
      { id: 4, name: 'Jet', age: 43 },
    ]).match(
      (data) => {
        const neatData = safeParseUsersData(data)
        setTimeout(() => {
          res.status(200).json(neatData)
        }, 500)
        return neatData
      },
      // @ts-ignore
      (error) => {
        dispatchServerSideError(req, res, error)
        return error
      }
    )
  }
)

export default handler

簡単ですが、以上です。