【入門編】 アサーションシグネチャ(asserts構文) – TypeScript実践ガイド

こんにちは!フロントエンド・アーキテクチャの現場を渡り歩いているチーフの私です。

TypeScriptを書き始めると、多くの人が「あれ、さっきまで文字列(string)だったはずなのに、なんでエラーになるんだ?」という型パズルに直面しますよね。特に、APIから返ってきたデータや、ユーザーが入力したフォームの値などを扱うとき、「本当にこのデータ、思っている通りの形をしているか?」を厳しくチェックしたくなります。

そんなとき、普通のif文でチェックしても、TypeScriptの賢いコンパイラ(型推論)は、そのブロックを抜けた後に「本当にその型になっているか」を忘れてしまうことがあります。

「あー、めんどくさい! この関数を通ったら、絶対この型だって決めつけて教え込みたいんだよ!」

そんな現場の叫びをスマートに解決してくれるのが、今回紹介する「アサーションシグネチャ(`asserts`構文)」です。
今回は、難しい専門用語のジャングルをいったん離れて、お買い物のレジ係の例え話と一緒に、優しく紐解いていきましょう。

—

1. 型ガードとアサーションの決定的な違い

まずは、おなじみの「型ガード(Type Guard)」を思い出してください。
例えば、お財布の中に現金が入っているか確認する場面を想像してください。

// お財布の中身チェック(今までのやり方)
function hasMoney(wallet: unknown): wallet is number {
return typeof wallet === “number”;
}

この `wallet is number` という書き方は、「この関数が `true` を返したら、この変数は数値だよ」とTypeScriptに優しく教える構文でした。

しかし、現場でよくあるのはこういう状況です。
「もしお金が入ってなかったら、その場でエラーを出して買い物を強制終了させたい!」

普通の関数でエラーを投げても、TypeScriptのコンパイラは「ふーん、エラーを投げるかもしれないけど、この関数のあとに変数の型が変わるかどうかまではちょっとわからないや」と、すっとぼけてしまうのです。

ここで登場するのが、「アサーションシグネチャ(`asserts`構文)」です。日本語にするなら「断言する!」「言い切る!」という力強い機能ですよ。

—

2. 身近な例え:「レジでの年齢確認」で考えてみる

コンビニでお酒を買う場面をイメージしてください。
店員さんは、お客さんの年齢が分からない(`unknown`)状態のとき、身分証の提示を求めます。

1. 「もし20歳未満だったら、販売を拒否(エラーをスロー)する!」
2. この関数のチェックを無事にすり抜けたということは、「お客さんは確実に20歳以上(`number`)である」と断言できる!

これをTypeScriptで書いてみましょう。

// お客さんの年齢データ(最初は正体がわからない unknown 型)
let customerAge: unknown = 22;

// 年齢が20歳以上であることを「断言」するアサーション関数
function assertIsAdult(age: unknown): asserts age is number {
// もし数値じゃなかったり、20未満だったら容赦なくエラーを投げる!
if (typeof age !== “number” || age < 20) { throw new Error("未成年への販売はお断りしております!"); } // ここを無事に通過できたら、「age は間違いなく number だ」とTypeScriptが確信します } どうでしょう? 関数の戻り値のところに `asserts age is number` という見慣れない書き方がありますね。これが「この関数がエラーを出さずに完了したら、引数の `age` は `number` 型に生まれ変わる(絞り込まれる)」という魔法の宣言です。 実際に使ってみると、その便利さが身に染みてわかります。 // まだ unknown 型なので、そのままでは数値用のメソッド(toFixedなど)は使えない // customerAge.toFixed(2); // エラー! // アサーション関数を実行! assertIsAdult(customerAge); // 【重要】ここで奇跡が起きる! // エラーが出ずにこの行に到達したということは、 // TypeScriptは customerAge が「絶対に number だ」と理解しています。 console.log(customerAge.toFixed(1)); // 22.0 (何のエラーも起きずに動く!) すごいですよね! `if文` で条件分岐して型を絞るボイラープレート(お決まりのコード)を何度も書かなくても、このチェック関数を1行挟むだけで、その後のコードでスマートに型安全の恩恵を受けられるんです。 ---

3. 初学者がつまずきやすいポイントと「大丈夫ですよ」のフォロー

新しい構文に出会うと、どうしても不安になりますよね。ここで、よくあるつまずきポイントをそっとフォローしておきます。

Q. 普通の関数と何が違うの?エラーを投げればいいだけじゃないの?

A. はい、JavaScriptの実行時(ブラウザで動いているとき)だけなら、`if文` で `throw new Error()` すれば動きは同じです。
しかし、TypeScriptのコンパイラは「その関数を実行したあとに、変数の型が変わっていること」を自動では察してくれません。
`asserts` を使うことで、TypeScriptに「この関数を通ったってことは、もう型が変わってるから安心して!」と、コンパイラを安心させてあげることができるんです。

Q. どんなときに使うのがベスト?

A. 実務では、以下のような場面で絶大な効果を発揮します。

  • 外部のAPIから帰ってきた「正体がわからないデータ(`unknown`)」を、画面で使う前に厳しくバリデーション(検証)するとき
  • 「絶対にこの要素は画面上に存在するはずだ!」というDOM要素の取得チェック
  • フォームの入力値が特定の型を満たしているかのガード

無闇矢鱈に使うものではありませんが、「ここを通過しないと先へ進めない」という門番(ガードマン)のような関数を作りたいときには、これ以上ない相棒になってくれます。

—

まとめ

今回は、TypeScriptのちょっとマニアックだけど実務でめちゃくちゃ頼りになる「アサーションシグネチャ(`asserts`構文)」について解説しました。

  • `asserts 変数名 is 型名` という構文を使うことで、関数内で例外を投げつつ、コンパイラに型の変化を教え込むことができる。
  • チェックを通過した後のコードでは、面倒な型の再確認なしでスッキリと安全にコードを書けるようになる。

TypeScriptの型システムは、私たち開発者を縛るための窮屈なルールではなく、「うっかりミスを事前に防いでくれる心強いアシスタント」です。

最初は見慣れない記号にドキッとするかもしれませんが、「おっ、ここに門番を配置しよう!」くらいの軽い気持ちで、ぜひ日々の開発に取り入れてみてくださいね。あなたのTypeScriptライフが、より快適で楽しいものになりますように!

コメント

タイトルとURLをコピーしました