1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

TypeScriptで「! (falsy)」を throw で弾くと、その後の型が保証されるのはなぜか

1
Posted at

はじめに

認証周りのTypeScriptをChatGPTを使用して書いていて、次のようなコードに巡り合いました。
今回は、なぜif (!token) throw new Error();を通過すると確定でStrigになるのかについて備忘録として残します。

let csrfToken: string | null = null;
if (!token) throw new Error();

このあとに token を使うと、型が string として扱われます。

return token; // stringとして扱われる

結論

if (!token) throw new Error();
この書き方は TypeScript の公式仕様である「型の絞り込み(Type Narrowing)」によって
token が string として確定します。

公式の根拠

TypeScript公式ドキュメント
公式ドキュメントを確認すると詳しく載ってますが、わかりにくいですが一言にすると
制御フロー(if / return / throw)によって型が絞り込まれる

なぜ string になるのか

元の型:
const token: string | null

対象コード:

if (!token) {
  throw new Error();
}

TypeScriptの解釈

  1. !token → falsy(null / undefined / “” など)
  2. 条件に入った場合 → throw により処理終了

つまり
この if を通過した時点で
「token は falsyではない」ことが保証される

型の変化

string | null

nullが除外される

string確定

ポイント

処理が終了する分岐(throw / return)は型を確定させる

よくあるパターン

パターン1

if (!token) throw new Error();
return token; // stringとして扱われる

パターン2

if (token === null) {
  throw new Error();
}

パターン3

if (token) {
  // tokenはstringとして扱われる
}

覚え方

ifで弾いた条件は、その後の処理では発生しない

if (!user) throw new Error();

// ここでは user は必ず存在する

さらに踏み込んだ理解

TypeScriptが内部で行っているのは以下です。
Control Flow Analysis(制御フロー解析)

イメージ
分岐ごとに「あり得る型」を削っていく

まとめ

TypeScript公式が用意している「Narrowing(型の絞り込み)」

if でチェックして throw させてしまえば、それより後ろのコードにはnullなどが入ることはないのでTypeScriptは「ここを通過したってことは、もう値は存在してるから型定義しているものが確定する」と解釈して型を絞り込んでくれる。

おわりに

この仕組みを理解しておくことで以下のメリットがある。

  • nullチェックがシンプルになる
  • 型安全なコードが書ける
  • 不要な型アサーションが減る
1
1
0

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
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?