こんにちは!Reactの世界へようこそ。チーフアーキテクトの私です。
Reactを触り始めて、最初に仲良くなるフックといえば、そう、`useState`ですよね。「画面のデータを覚えておいてくれる便利なメモ帳」のような感覚で、直感的に使えるのが魅力です。
でも、ここにTypeScriptという頼もしい(だけど時にはちょっと厳しい)相棒が加わった途端、こんな赤い波線エラーに頭を悩ませたことはありませんか?
- 「プロパティ ‘xxx’ は型 ‘unknown’ に存在しません」
- 「型 ‘null’ を型 ‘string’ に割り当てることはできません」
「動くには動くけど、なんだか型定義にモヤモヤする……」
大丈夫ですよ!最初はみんなそこでつまずきます。今日は、身近な例えを交えながら、`useState`の型推論とジェネリクスのモヤモヤをスッキリ解消していきましょう!
—
1. `useState`の型推論は「優秀なレジ打ちさん」
まずは、TypeScriptが裏でどうやって型を理解しているのかを知ることから始めましょう。
例えば、お買い物カゴをイメージしてください。カゴの中に最初に「りんご(文字列)」を入れたとします。すると、優秀なレジ打ちさん(TypeScript)は、「あ、このカゴには文字しか入らないんだな」と勝手に察してくれます。これが型推論です。
import { useState } from ‘react’;
export function ShoppingCart() {
// 初期値に文字列の “りんご” を渡しているので、
// TypeScriptは自動的に item の型を string と判断してくれます
const [item, setItem] = useState(“りんご”);
// ここで setItem(123); とやろうものなら、レジ打ちさんが
// 「おいおい、文字列を想定してるのに数字を入れるなよ!」と怒ってくれます(エラー)
return (
現在のカゴの中身: {item}
);
}
すごいですよね。何も指定しなくても、初期値を見て勝手に安全を守ってくれる。これが`useState`の基本の形です。
—
2. でも、最初は「空っぽ(null)」の時だってありますよね?
さて、ここからが現場のリアルです。
お買い物カゴを例にするなら、「お店に入ったばかりの時は、まだ何も選んでいない(カゴの中身は空っぽ= `null`)」という状況、よくありますよね。
ここで初学者がハマりがちな罠があります。
// ❌ やりがちなミス
// 初期値に null を入れたので、TypeScriptは「このカゴは一生 null のままだ」と思い込んでしまう
const [user, setUser] = useState(null);
この状態で、あとからAPIでユーザー情報を取得してきて `setUser({ name: “田中太郎”, age: 28 })` なんて入れようとすると、TypeScriptは「おっと、空っぽのカゴに急に人間が入ってきたぞ!」とパニックを起こしてエラーを出します。
救世主登場:ジェネリクス `` という「カゴの指定席」
こういうときこそ、ジェネリクス(型引数)の出番です!
ジェネリクスと聞くと難しそうに聞こえますが、要するに「このカゴには、将来こういうデータが入る予定だから、今のうちに予約席を作っておいてね!」とTypeScriptに教えてあげる仕組みのことです。
書き方は簡単。`useState<型>(初期値)` と、山括弧 `<>` を使って指定します。
import { useState } from ‘react’;
// ユーザー情報の型をあらかじめ定義しておきます
type User = {
name: string;
age: number;
};
export function UserProfile() {
// 🌟 ここがポイント!
// 「初期値は null だけど、入るかもしれないデータは User 型(または null)」と明示する
const [user, setUser] = useState
const handleLogin = () => {
// これで怒られずにデータをセットできます!
setUser({ name: “田中太郎”, age: 28 });
};
return (
{user ? (
こんにちは、{user.name}さん({user.age}歳)!
) : (
ログインしていません。
)}
);
}
この `useState
「今はまだデータがない(`null` や `undefined`)」けれど、「後からデータが入ってくる」という非同期的なWeb制作の現場では、このunion型(`|` でつなぐ書き方)が最高の相棒になります。
—
3. 現場で役立つ!安全な取り扱いのコツ
型定義ができるようになると、次は画面に表示するときの「安全確認」が大切になってきます。
例えば、さっきの `user` が `null` の可能性があるのに、うっかり `user.name` と書いてしまうと、画面が真っ白になる恐怖のエラー(`Cannot read properties of null`)が起きてしまいます。
TypeScriptはそれを防ぐために、しっかりとチェックを強制してくれます。
1. オプショナルチェーニング (`?.`) を使う
`user?.name` と書くことで、「もし `user` が存在していれば `name` を取ってきてね、`null` ならそのままスルーしてね」という安全なアクセスができます。
2. 早期リターンや三項演算子でガードする
先ほどのコードのように、`user ? (…) : (…)` とあらかじめ `null` の場合分けをしてあげることで、そのブロックの中では安心して `user.name` を使えるようになります。
—
まとめ
いかがでしたでしょうか?
今日のポイントをギュッと凝縮して振り返ってみましょう。
- 基本の型推論: 初期値を渡せば、レジ打ちさん(TypeScript)が勝手に型を推論してくれる!
- 初期値が `null` や `undefined` の場合: 将来入るデータを見越して、ジェネリクス `useState
(null)` で予約席を作ろう! - 安全な取り扱い: `null` の可能性を考慮して、`?.` や条件分岐で優しくガードしよう!
TypeScriptの型定義は、最初はあなたを縛る窮屈なルールのように感じるかもしれませんが、慣れてくると「自分のコードのバグを事前に見つけて守ってくれる、最高に頼もしい相棒」に変わります。
焦らず、一歩ずつ自分のものにしていきましょう。あなたのReactライフを、チーフアーキテクトとしてこれからも応援しています!

コメント