🧑‍💻

【TypeScript】Result型を定義してエラーハンドリングを楽にする

2022/12/18に公開約2,400字

はじめに

TypeScriptでResult型を定義する方法はいくつかありますが、生成時や処理時の書き方が個人的に分かりにくいものだったので、初心者の方でも簡単に使えるResult型を作成したいと思います。

Result型とは?

Result型とは、何かしらの処理において、成功または失敗を表現できる型です。
これにより、try, catchでの苦悩を解放することができるようになります。

try, catchの問題点

TypeScriptでは、try, catchcatchした例外は、anyとして扱われます。
これでは、TypeScriptの型安全性の強みを全く活かすことができません。

try {
    doSomething();
} catch(e) {
    if (e instanceof HogeError) {}
    else if (e instanceof FugaError) {}
    .
    .
    .
    // eの型がanyであるため、絞ろうにも絞れない
}

完成コード

今回作成したResult型がこちらとなります。
工夫して点としては、Result.success()またはResult.failure()で生成できるようにしたことや、結果処理を簡単にできるようにwhen()を実装したことです。

class Result<T, E extends Error> {
  private readonly value: T | E;

  private constructor(value: T | E) {
    this.value = value;
  }

  static success<T>(value: T): Result<T, Error> {
    return new Result<T, Error>(value);
  }

  static failure<E extends Error>(error: E): Result<any, E> {
    return new Result<any, E>(error);
  }

  when({
    success,
    failure,
  }: {
    success: (data: T) => any;
    failure: (error: E) => any;
  }) {
    if (this.value instanceof Error) {
      return failure(this.value);
    } else {
      return success(this.value);
    }
  }
}

使い方

使い方は簡単で、成功時のResultを生成したいときにはResult.success()、失敗時のResultを生成したいときはResult.failure()を使用するだけです。

Result.success(返したい値);
Result.failure(投げたいエラー);

また、返ってきたResult型に対して、成功時と失敗時の処理を実装する際には、when()を使用するだけです。

const result = something();
result.when({
  success(data) {
    成功時の処理
  },
  failure(error) {
    失敗時の処理
  },
});

使用例

class HogeError extends Error {}

class FugaError extends Error {}

// 戻り値について 
// 成功時:string 
// 失敗時:HogeErrorまたはFugaError
function foo(value: string): Result<string, HogeError | FugaError> {
  if (value === "foo") {
    return Result.success("success");
  } else {
    // throwの代わりにResult.failure()をreturnする
    return Result.failure(new HogeError());
  }
}
// 例1
const result1 = foo('foo');
result1.when({
  success(data) { // dataの型はstring
    // 実行される
    console.log(data); // foo
  },
  failure(error) { // errorの型はHogeErrorまたはFugaError
    // 実行されない
    if (error instanceof HogeError) {}
    else if (error instance of FugaError) {}
  },
});

// 例2
const result2 = foo('bar');
result2.when({
  success(data) { // dataの型はstring
    // 実行されない
  },
  failure(error) { // errorの型はHogeErrorまたはFugaError
    // 実行される
    if (error instanceof HogeError) {}
    else if (error instance of FugaError) {}
  },
});

Discussion

ログインするとコメントできます