インターラプト開発者ブログ

インターラプトのプロダクト・サービスに関する開発ブログ

ts-resultsで安全にasync awaitを使う

TypescriptやJavaScriptで開発をしていると、async awaitをよく使います。コールバック関数のネストを防ぎ、コードのリーダビリティを保ちながらコードを書くことが出来るため有用なシンタックスです。

awaitの注意点

async functionでは、awaitを使う事ができるようになりますが、非同期処理内でエラーが発生した場合にキャッチする方法がないことに注意が必要です。

const func = async () => {
  const response = await axios.get('http://....');
  console.log('エラーが発生するとここが実行されない');
}

axios内で通信エラーが発生した場合は、例外エラーが発生し、それ以降の処理が実行されません。例外エラーを処理したい場合は、axiosの返すPromiseで.catchを使うしかありません。

const func = async () => {
  const response = await axios.get('http://....')
  .catch( error => error);
}

このようにすることで、例外エラーがスローされることなく、responseにエラーが返ります。

しかし、この時にresponseの型は AxiosResponse | AxiosError となり、responseにどちらの型が含まれているのかわからなくなってしまいます。

厳密には各型に含まれるフィールドから判定すれば良いのですが、型を推定するにはasを使う必要があり、コード量が増えてしまいます。かといって、.catch内で書いてしまうと、またコールバックのネストになってしまいます。

ts-resultsでラップする

ts-results https://github.com/vultix/ts-results

ts-resultsは、RustにあるOption型やRusult型をTypeScriptで実装したもので、コンパイルタイムで型チェックの機能を持ちます。

import { Ok, Err, Result } from 'ts-results';
const func = async () => {
  const result = await axios.get('http://....')
  .then( res => Ok(res))
  .catch( error => Err(error));
}

この場合、resultには

Result<AxiosResponse, AxiosError>

という型の値が返ります。 左の型が、Ok型となり、右の型がErrの型となります。 左と右は他の様々な型にすることが出来ます。

OkまたはErrどちらかの状態を持つことが出来るのがこのResult型となります。

エラーかどうか判定する

Result型は、簡単にエラーかどうか判定する事が出来ます。

import { Ok, Err, Result } from 'ts-results';
const func = async () => {
  const result = await axios.get('http://....')
  .then( res => Ok(res))
  .catch( error => Err(error));
}

if (result.err) {
  return result;
}

エラーがある場合は.err、エラーがない場合は.okにtrueが入ります。これによって、エラーがあった場合は処理を進めずに例外エラーを発生させることもなくResult型をそのまま返すことも出来ます。

値を取得する

特にエラーもなく、その後の処理を行いたい場合は

result.val

こちらを使用出来ますが、型の推定がうまくいかない場合があるので、.unwrapを使用します。

import { Ok, Err, Result } from 'ts-results';
const func = async () => {
  const result = await axios.get('http://....')
  .then( res => Ok(res))
  .catch( error => Err(error));
}

if (result.err) {
  return result;
}

const response = result.unwrap();

unwrapは、Result型からokだった場合に値を返します。errだった場合は、エラーになるので、あらかじめerrが入っていないか確認する必要があります。

このように、async awaitにts-resultsを使うことによって、安全にシステムを開発する事が出来ます。