カテゴリ: React 更新日: 2026/03/25

React(TypeScript)で学ぶStateの型推論と型指定の違い!型安全なState管理を初心者向けにやさしく解説

Stateの型推論と型指定の違い
Stateの型推論と型指定の違い

先生と生徒の会話形式で理解しよう

生徒

「Reactでボタンを押した回数みたいな“状態”を持てるって聞きました。TypeScriptだと型ってどうなるんですか?」

先生

「ReactのStateは、TypeScriptだと“型推論”で自動的に型が決まることが多いです。ただし、場面によっては自分で“型指定”した方が安全になります。」

生徒

「型推論と型指定って、何が違うんですか?どっちを使えばいいのか迷います…」

先生

「違いは“最初の値だけで決めて良いか”と“これから入る値の種類を先に決めたいか”です。たとえば、最初は空っぽだけど後でデータが入るStateは、型指定がとても役に立ちます。」

生徒

「なるほど…!まずは、基本から順番に教えてください!」

1. ReactのStateとは?TypeScriptと一緒に考える

1. ReactのStateとは?TypeScriptと一緒に考える
1. ReactのStateとは?TypeScriptと一緒に考える

ReactのState(ステート)は、画面の中で変化する情報を入れておく箱です。たとえば「入力欄の文字」「チェックのオンオフ」「読み込み中かどうか」「ボタンを押した回数」など、ユーザーの操作や通信結果で変わるものをStateで管理します。

TypeScriptは型(かた)を使って「この箱には数字だけ」「この箱には文字だけ」のようにルールを決められます。型があると、間違った値を入れようとした瞬間に気づけるので、バグ(不具合)を減らせます。ReactとTypeScriptを組み合わせると、型安全(かたあんぜん)なState管理がしやすくなります。

用語メモ:「型推論」は、TypeScriptがコードを見て自動で型を考えてくれる仕組みです。「型指定」は、開発者が先に型をはっきり書いて決めることです。

2. Stateの型推論とは?useStateが“最初の値”から型を決める

2. Stateの型推論とは?useStateが“最初の値”から型を決める
2. Stateの型推論とは?useStateが“最初の値”から型を決める

ReactではStateを作るときにuseStateをよく使います。TypeScriptでは、useStateに入れる最初の値を見て、Stateの型を自動で決めることが多いです。これがStateの型推論です。


import React, { useState } from "react";

export default function App() {
  // 最初の値が 0 なので、count は number(数字)だと推論される
  const [count, setCount] = useState(0);

  return (
    

回数:{count}

); }
(画面に「回数:0」が表示され、ボタンを押すたびに数字が1ずつ増えて表示されます)

この例では、最初の値が数字の0なので、TypeScriptは「countは数字だ」と判断します。その結果、setCount("こんにちは")のように文字を入れようとすると、エラーとして教えてくれます。初心者にとっては、間違いが早めに見つかるのが大きな安心ポイントです。

3. Stateの型指定とは?“あとで入る値”まで見越して先に決める

3. Stateの型指定とは?“あとで入る値”まで見越して先に決める
3. Stateの型指定とは?“あとで入る値”まで見越して先に決める

一方で、最初の値だけでは型がうまく決まらないことがあります。たとえば「最初は何もない(null)けど、あとでユーザー情報が入る」Stateです。最初がnullだと、TypeScriptは「nullしか入らない箱」と勘違いしやすくなります。

よくあるつまずき:最初に null や空配列 [] を入れたせいで、あとから正しいデータを入れようとしても型エラーになることがあります。

import React, { useState } from "react";

type User = {
  id: number;
  name: string;
};

export default function App() {
  // User か null が入る、と先に型指定する(ジェネリクス)
  const [user, setUser] = useState<User | null>(null);

  return (
    
{user ?

こんにちは、{user.name}さん

:

ユーザー未設定

}
); }
(最初は「ユーザー未設定」と表示され、ボタンを押すと「こんにちは、さくらさん」に変わります)

ここで出てきたジェネリクスは、「型の入れ物に、あとから型を差し込む書き方」です。useState<User | null>のように書くと、「userにはUserかnullが入る」と宣言できます。こうしておくと、最初がnullでも、あとでUserを入れられます。

また、union型(ユニオンがた)は「AかBのどちらか」という意味です。ここでは「Userかnull」のどちらか、というルールになります。現実の例えだと、「席には人が座っているか、空席(null)か」のようなイメージです。

4. 型推論と型指定の“違い”を一言でいうと?

4. 型推論と型指定の“違い”を一言でいうと?
4. 型推論と型指定の“違い”を一言でいうと?
  • 型推論:最初の値を見て、TypeScriptが「このStateはたぶんこれ!」と自動で決める
  • 型指定:最初の値だけに頼らず、「このStateには将来これが入る」と先にルールを決める

型推論は書く量が少なくて楽です。ですが、アプリが少し大きくなると「最初は空」「あとで入る」「複数の形がある」といったStateが増えます。そんなとき、型指定を使うと未来の自分やチームを助ける説明書になります。

5. 初心者が迷いやすいパターン:空配列・空オブジェクトのState

5. 初心者が迷いやすいパターン:空配列・空オブジェクトのState
5. 初心者が迷いやすいパターン:空配列・空オブジェクトのState

特に初心者が混乱しやすいのが、配列(リスト)やオブジェクト(まとまり)のStateです。たとえば、最初はデータがないので空配列で始めたいことがあります。ここで型推論だけに頼ると、意図しない型になってしまうことがあります。


import React, { useState } from "react";

type Todo = {
  id: number;
  title: string;
  done: boolean;
};

export default function App() {
  // 配列に Todo が入る、と型指定しておくと安全
  const [todos, setTodos] = useState<Todo[]>([]);

  return (
    

件数:{todos.length}

); }
(最初は「件数:0」で、ボタンを押すと件数が増えていきます)

このようにuseState<Todo[]>([])と書くと、「この配列にはTodoだけが入る」と決められます。ReactのState管理で配列を扱うときは、あとから追加・削除・更新がよく起きるので、型指定があると安心です。

6. “nullチェック”と型安全:安全に読み出す考え方

6. “nullチェック”と型安全:安全に読み出す考え方
6. “nullチェック”と型安全:安全に読み出す考え方

型指定でUser | nullのようにすると、読み出すときに「nullかもしれない」ことを忘れにくくなります。これがTypeScriptの大事なところです。もしnullのままuser.nameに触ろうとすると、画面が止まる原因になることがあります。

そこでReactでは、条件分岐(条件によって表示を変える)と組み合わせて安全に表示します。上の例のuser ? ... : ...は「userがあるならA、ないならB」という意味です。TypeScriptの型指定とReactの条件分岐は相性が良く、初心者でも“事故”を減らせます。

例え:冷蔵庫を開ける前に「牛乳があるか」を確認する感じです。あるならコップに注げますが、ないのに注ごうとすると困ります。nullチェックは、この確認作業に似ています。

7. どんなときに型推論で十分?どんなときに型指定が必要?

7. どんなときに型推論で十分?どんなときに型指定が必要?
7. どんなときに型推論で十分?どんなときに型指定が必要?

目安として、次のように考えると選びやすいです。ReactのuseStateはどちらでも使えますが、アプリの意図をはっきりさせたいときは型指定が強い味方です。

型推論で十分なことが多い例
  • 最初から最後まで同じ種類の値が入る(数字、文字、真偽値など)
  • 初期値がはっきりしていて、あとで形が変わらない
  • 学習用の小さなコンポーネントで、まず動きを理解したい
型指定をおすすめしたい例
  • 最初はnullや空で、あとでデータが入る(API通信、ログイン情報など)
  • 配列やオブジェクトで、中身の形を守りたい
  • 「AかBか」のように複数パターンがあり、union型で表したい

特に「PropsとStateを型安全にしたい」「TypeScriptでReactのバグを減らしたい」と考えるなら、Stateの型指定は避けて通れません。小さなうちは型推論で書きやすく、少し複雑になったら型指定で守りを固める、という順番が自然です。

8. State型の設計で意識したいこと:入力フォームを例にする

8. State型の設計で意識したいこと:入力フォームを例にする
8. State型の設計で意識したいこと:入力フォームを例にする

入力フォームのStateは、初心者がReactのState管理を学ぶときに定番です。たとえば「名前」と「年齢」の入力をまとめて持つ場合、オブジェクトで管理します。ここでも型指定をしておくと、フィールド名の打ち間違いを防げます。


import React, { useState } from "react";

type FormState = {
  name: string;
  age: number;
};

export default function App() {
  const [form, setForm] = useState<FormState>({ name: "", age: 0 });

  return (
    

名前:{form.name}

年齢:{form.age}

); }
(「名前」「年齢」が表示され、ボタンを押すと表示内容が更新されます)

このように型指定しておくと、たとえばageに文字を入れたり、存在しないプロパティ名を書いたりしたときに、TypeScriptが「それは違う」と止めてくれます。ReactのState管理は自由度が高い分、型安全で守ると安心して作業できます。

9. “型推論が強すぎる”ときの対処:リテラル型と広げたい型

9. “型推論が強すぎる”ときの対処:リテラル型と広げたい型
9. “型推論が強すぎる”ときの対処:リテラル型と広げたい型

TypeScriptはとても賢いので、時々「推論が細かすぎる」ことがあります。たとえば、Stateに入れる文字が「loading」「success」「error」のように決まっている場合は、むしろ細かい方が便利です。でも「あとでいろいろな文字が入る」なら、広い型にしたいこともあります。

こうした状態は、ステータス(状態の種類)としてよく出てきます。ここではunion型で安全にしつつ、意図をはっきりさせます。


import React, { useState } from "react";

type Status = "idle" | "loading" | "success" | "error";

export default function App() {
  const [status, setStatus] = useState<Status>("idle");

  return (
    

状態:{status}

); }
(ボタンを押すと「状態:idle」が「loading」「success」「error」に切り替わって表示されます)

このように型指定すると、間違って"loadding"のように打ち間違えてもエラーで気づけます。ReactのStateは画面の見た目や動きに直結するので、ステータス管理は型安全にしておくとトラブルが減ります。

10. setStateの型も一緒に決まる:更新方法が安全になるメリット

10. setStateの型も一緒に決まる:更新方法が安全になるメリット
10. setStateの型も一緒に決まる:更新方法が安全になるメリット

useStateは、State本体だけでなく、更新用の関数であるsetState(例:setCountsetUser)の型も自動で決めます。つまり、型推論や型指定が正しくできていると、更新の仕方まで安全になります。

たとえば数字のStateなら、setCount(count + 1)のように数字の計算が自然に書けますし、文字のStateなら文字の処理が中心になります。逆に、型があいまいだと「今入っているのは数字?文字?」と迷いやすくなり、コードも読みづらくなります。

またReactでは、Stateの更新に関数形式(前の値を受け取って次の値を返す)を使うことがあります。これは「連続でボタンを押したときでも、前の値を正しく元にして更新する」ための書き方です。TypeScriptの型が合っていれば、この関数形式でも引数と戻り値の型がそろい、更新ミスを防げます。

例え:レシートの合計金額を更新するときに、「前の合計に新しい商品代を足す」方が安全です。いきなり合計を決め打ちするより、前の値を元に計算するとズレにくい、という感覚に近いです。

まとめ

まとめ
まとめ

ReactとTypeScriptを組み合わせたState管理は、アプリ開発において非常に重要な基礎でありながら、最初につまずきやすいポイントでもあります。特に「型推論」と「型指定」の違いを正しく理解することは、今後の開発効率やバグの少なさに大きく影響します。本記事で解説してきた内容を振り返りながら、重要なポイントを整理していきましょう。

まず、型推論はTypeScriptが自動的に型を判断してくれる便利な仕組みです。useStateに初期値を渡すことで、その値の型からStateの型が決まります。たとえば数値であれば数値型、文字列であれば文字列型といった具合に、コードを書く手間を減らしつつ安全性を確保できます。初心者が最初にReactのState管理を学ぶ際には、この型推論を活用することで、シンプルに理解を進めることができます。

一方で、実務や少し複雑なアプリケーションになると、型推論だけでは対応しきれないケースが増えてきます。たとえば初期値がnullである場合や、あとからAPIのデータが入るようなState、配列やオブジェクトで複雑なデータ構造を扱う場合です。このような場面では、型指定を行うことで、将来入る値の形をあらかじめ明確にし、安全なコードを書くことができます。

特に重要なのが、nullを含む型や配列の型です。これらは型指定をしないと、意図しない型として扱われてしまい、後からエラーの原因になります。たとえばユーザー情報を扱うStateでは、最初はnullで後からデータが入ることが多いため、union型を使ってUserかnullという形で型を定義することが重要です。

また、配列を扱う場合も同様です。空配列で初期化すると型が曖昧になりやすいため、どのようなデータが入るのかを明確にすることで、追加や更新の処理を安全に行うことができます。ReactのStateは頻繁に更新されるため、型が曖昧なままだとバグの温床になりやすいのです。

さらに、フォーム入力やステータス管理など、実際の開発でよく使うパターンでは、型指定の重要性がよりはっきりと見えてきます。入力フォームではオブジェクト型を使って複数の値をまとめて管理し、ステータス管理では決まった文字列だけを扱うことで、誤入力を防ぐことができます。

ReactのState管理においては、型推論と型指定を適切に使い分けることがポイントです。小さなコンポーネントや単純な値であれば型推論で十分ですが、データの構造が複雑になったり、将来的な変更が想定される場合は、型指定を行うことでコードの可読性と安全性が向上します。

最後に、TypeScriptを使う最大のメリットは、コードを書いている段階でミスに気づけることです。Reactと組み合わせることで、画面の動きとデータの整合性を同時に守ることができます。これは開発者だけでなく、チーム全体にとっても大きなメリットとなります。


import React, { useState } from "react";

type Item = {
  id: number;
  name: string;
};

export default function App() {
  const [items, setItems] = useState<Item[]>([]);

  const addItem = () => {
    setItems([...items, { id: items.length + 1, name: "商品" }]);
  };

  return (
    <div>
      <p>件数:{items.length}</p>
      <button onClick={addItem}>追加</button>
    </div>
  );
}
(ボタンを押すたびに件数が増えて表示されます)
先生と生徒の振り返り会話

生徒

「型推論って便利ですけど、全部それでいいわけじゃないんですね」

先生

「その通りです。簡単な場合は型推論で十分ですが、将来のデータの形を考えると型指定が必要になる場面も多いです」

生徒

「特にnullとか配列のところは注意が必要だと感じました」

先生

「良い気づきですね。そこをしっかり意識するだけで、エラーをかなり減らせます」

生徒

「フォームやリストの管理でも型が役立つのがよく分かりました」

先生

「ReactのState管理は自由度が高い分、型でルールを決めることがとても大切です」

生徒

「これからは最初の値だけじゃなくて、その先の使い方も考えて型を決めていきます」

先生

「その意識があれば、型安全なReact開発がしっかり身につきますよ」

カテゴリの一覧へ
新着記事
New1
React
Reactでファイルアップロードを実装する方法を解説!Fetch APIで画像やPDFを送る仕組みを初心者向けに紹介
New2
React
Reactのリストとkeyをやさしく解説!初心者でもわかるリストアイテムをコンポーネントに分割する方法
New3
React
React RouterのuseNavigateフックの使い方を完全解説!初心者でもわかるプログラム的なページ遷移
New4
React
Reactでよくある型エラーと解決法をやさしく解説!初心者でも安心できる型安全な考え方
人気記事
No.1
Java&Spring記事人気No1
React
Reactとは?初心者でもわかるReact.jsの基本概念と特徴をやさしく解説
No.2
Java&Spring記事人気No2
React
React Context APIのデバッグ方法を完全解説!React DevToolsで中身を丸見えにする方法
No.3
Java&Spring記事人気No3
React
React Routerとは?シングルページアプリのルーティングを初心者向けにわかりやすく解説
No.4
Java&Spring記事人気No4
React
ReactとTypeScriptの環境構築をやさしく解説!Viteとtsconfigの設定も丁寧に紹介
No.5
Java&Spring記事人気No5
React
Reactの学習ロードマップ!初心者が最短で習得する流れを完全ガイド
No.6
Java&Spring記事人気No6
React
Reactでファイルアップロードを実装する方法を解説!Fetch APIで画像やPDFを送る仕組みを初心者向けに紹介
No.7
Java&Spring記事人気No7
React
create-react-appでReactプロジェクトを作成する手順を初心者向けに完全解説!
No.8
Java&Spring記事人気No8
React
React開発におすすめのVSCode拡張機能まとめ!初心者でもすぐ使える便利ツール紹介