こんにちは!TypeScriptの世界へようこそ。チーフアーキテクトの私です。
日々、たくさんのコードを書いていると、「ああっ、また君か!」と頭を抱えたくなるエラーに出会いませんか?そう、JavaScriptやTypeScriptの歴史の中で、おそらく世界中の開発者が一番お世話になり、そして一番悩まされてきたエラー……。
そう、「Cannot read properties of undefined (reading ‘〇〇’)」(undefinedのプロパティを読み込めません)です。
画面が真っ白になったり、コンソールに赤字がずらりと並んだりするあの瞬間、本当に冷や汗が流れますよね。「TypeScriptを使っていれば、型が守ってくれるはずじゃなかったの!?」と叫びたくなる気持ち、痛いほどよく分かります。
でも、安心してください。TypeScriptには、そんな「nullやundefinedの魔物」をピシャリと追い払ってくれる、とっても頼もしい秘密兵器が用意されているんです。それが今回ご紹介する `NonNullable
難しく聞こえるかもしれませんが、身近な例えを交えながらゆっくり紐解いていきますので、肩の力を抜いてお付き合いくださいね。
—
1. 「なんでも入れられる箱」の落とし穴
TypeScriptを学び始めると、`string`(文字列)やキスト、`number`(数値)といった基本的な型を覚えますよね。
例えば、ユーザーの名前を管理する変数を考えてみましょう。
let userName: string = “田中さん”;
これなら安心です。「`userName`には絶対に文字列が入る」とTypeScriptが太鼓判を押してくれています。
しかし、実際のWeb開発はそんなに甘くありません。データベースからデータを取ってくるまでの間や、ユーザーがまだ入力していない瞬間など、世の中には「まだ値がない(= undefined)」、あるいは「データが存在しない(= null)」という状態が山ほどあります。
そこで、私たちはついついこんな型定義をしてしまいがちです。
// 文字列かもしれないし、nullやundefinedかもしれない
let inputData: string | null | undefined = “こんにちは”;
この `string | null | undefined` は、いわば「何が入っているか開けてみるまで分からない、開けたら空っぽかもしれないおもちゃ箱」のようなものです。
この箱からデータを取り出して、そのまま文字数(`.length`)を測ろうものなら……TypeScriptのコンパイラは「ちょっと待って!中に`null`が入っていたらエラーになりますよ!」と優しく、しかし厳しく止めてくれます。
2. ゴミをきれいに分別する救世主:`NonNullable`
ここで登場するのが、今回の主役である `NonNullable
イメージしてみてください。あなたは今、おもちゃ箱の中に混ざってしまった「プラスチックのオモチャ(有効なデータ)」と、「ただのホコリやゴミ(`null` や `undefined`)」を仕分けています。
`NonNullable
百聞は一見に如かず。実際にコードを見てみましょう。
// 色々なものが混ざった型(ユニオン型)を用意します
type MaybeString = string | null | undefined;
// NonNullableを使って、nullとundefinedを排除した新しい型を作ります
type CleanString = NonNullable
// 結果、CleanString は実質的に以下のようになります:
// type CleanString = string;
たったこれだけです!
`MaybeString` という「何が入っているか分からない箱」から、`NonNullable` を通すことで、`string` という純粋な型だけを取り出すことができました。
これで、もう「中身が `null` だったらどうしよう……」とビクビクしながらコードを書く必要がなくなります。
—
3. 実務でどう使うの?具体的なシーンを覗いてみよう
「理屈は分かったけれど、実際のWeb制作やアプリ開発の現場でどう使うの?」という疑問が湧いてきますよね。よくある実践的な例をいくつか見てみましょう。
シーン1:APIから送られてくるユーザーデータの整理
Webサイトを作るとき、サーバーからユーザーのプロフィール情報を取得することがよくあります。年齢(`age`)のデータは、登録されていないと `null` が返ってくることがあります。
// サーバーから返ってくるかもしれないユーザー情報の型
interface UserProfile {
id: number;
name: string;
age: number | null | undefined; // 年齢は未登録の可能性がある
}
// ここで、ageの型だけをキレイに取り出したい!
type ValidAge = NonNullable
// 出来上がる型:number
もし、アプリの別の場所で「年齢が絶対に登録されていることが前提の処理」を書く場合、この `ValidAge`(つまり `number`)を使うことで、余計な `if (age !== null)` のチェックを省略して、スッキリとしたコードを書くことができます。
シーン2:フォームの入力値のバリデーション後
ユーザーが入力フォームに打ち込んだ値を受け取る際、最初は「未入力(`undefined`)」や「未選択(`null`)」の可能性があります。しかし、入力チェック(バリデーション)を無事に通過したあとのデータは、もう `null` や `undefined` であるはずがありません。
// 入力フォームの現在の値(最初は空っぽかもしれない)
let commentInput: string | null = null;
// バリデーションを通過したと仮定して、確実に値が存在する状態にする
function handleValidComment(comment: NonNullable
// この中では、commentは100% string型として扱えます!
console.log(`送信されたコメント: ${comment.toUpperCase()}`);
}
// 試しに値をセットして関数を呼んでみる
commentInput = “TypeScriptの勉強中!”;
if (commentInput !== null) {
// TypeScriptに「この瞬間、nullじゃないよ」と教えてあげる
handleValidComment(commentInput);
}
このように、型を厳格に絞り込むことで、予期せぬバグの温床をあらかじめ断つことができるのです。これが、TypeScriptを導入する最大の醍醐味でもあります。
—
4. チーフアーキテクトからのメッセージ
初学者のうちは、TypeScriptの型エラーに出会うたびに「また怒られた……」と心が折れそうになることもあるでしょう。私も昔はそうでした。画面の向こうのコンパイラが、まるで鬼の形相で自分を監視しているように感じたものです。
でも、見方を変えてみてください。TypeScriptの型エラーや、今回ご紹介した `NonNullable
本番環境でユーザーがボタンを押した瞬間にアプリがクラッシュするのを、あなたの代わりに未然に防いでくれているのですから。
最初は難しく感じる型操作も、ひとつずつ引き出しを増やしていけば、パズルを解くように楽しくなってきます。今日知った `NonNullable
焦らず、自分のペースで一歩ずつ進んでいきましょう。あなたのTypeScriptライフが、より快適で楽しいものになるよう、私はいつも応援しています!

コメント