はじめに
認証周りの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の解釈
-
!token→ falsy(null / undefined / “” など) - 条件に入った場合 → 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チェックがシンプルになる
- 型安全なコードが書ける
- 不要な型アサーションが減る