search
LoginSignup
0
Organization

unreachableを活用しよう

unreachableってなんですか

unreachableとは下記で示される関数のことで、要するに到達して欲しくない & し得ない場所に防御的に使う関数です。

export const unreachable = (msg?: string) => {
  throw new Error(msg ?? 'Something went wrong')
}

unreachableの活用方法

私はこのunreachableの主に2つのユースケースで使用することが多いです。

パターン1: 三項演算子のチェック

type SomeUnion = 'foo' | 'bar'
const fooOrBar: SomeUnion = 'foo'
const hogeOrFuga =
  fooOrBar === 'foo'
    ? 'hoge'
    : fooOrBar === 'bar'
    ? 'fuga'
    : unreachable('Unexpected value')

TypeScriptの型システムで守られていても、実際にSomeUnionの値が入ってくるかは保証できないため、このようにunreachableで検知できるようにしています。

パターン2: OptionalのUnwrap

unreachablenever型を返す関数です。never型を返す関数とはreturnされることの無い関数(throwで中断されたり、無限ループで永遠に終わらないなど)という意味です。

このneverの特性を活かして下記のようにoptional値の強制Unwrapが可能です。

export const API_ENDPOINT = process.env.API_ENDPOINT ?? unreachable("API_ENDPOINT is not defined.)

少しだけ解説すると、process.env.API_ENDPOINT の型は string | undefined として扱われます。

もしprocess.env.API_ENDPOINTundefined だった場合、 unreachable が実行されプログラムは中断されるということが型情報から判別可能です。

そのためこの先プログラムが正しく動くという事は、unreachableを通らないこと、すなわち process.env.API_ENDPOINTstring であるという型推論が可能となります。

特に環境変数などの値は相性がよいので、アプリのコードの随所で process.env を参照せずに一箇所にまとめてUnwrapし管理すると良いと思います。

P.S.

特にパターン2のUnwrapのケースでは、invariantを使うよりもunreachable使ったほうが、スマートな気がするなぁ...なんて

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
0