カテゴリ: React 更新日: 2026/02/15

TypeScriptでuseEffectを型安全に使う方法を完全解説!初心者でもわかるReactの基本

TypeScriptでuseEffectを型安全に使う方法
TypeScriptでuseEffectを型安全に使う方法

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

生徒

「ReactでuseEffectってよく出てきますけど、TypeScriptを使うときは型をどうすればいいんですか?」

先生

「useEffectは副作用を扱うフックですね。TypeScriptでも型安全に使うことができますよ。」

生徒

「副作用って何ですか?難しそうでよく分かりません…」

先生

「副作用とは『画面の表示以外の処理』のことです。例えばデータをサーバーから取ってきたり、タイマーを動かしたりするのが副作用です。」

生徒

「なるほど!それをTypeScriptで型安全にする方法を知りたいです!」

先生

「では具体的にuseEffectを型安全に使う方法を一緒に見ていきましょう。」

1. useEffectの基本的な使い方

1. useEffectの基本的な使い方
1. useEffectの基本的な使い方

useEffectは、Reactコンポーネントの中で副作用を処理するために使います。例えば「コンポーネントが画面に表示されたときに一度だけ動く処理」や「特定の値が変わったときに動く処理」を書けます。


import React, { useEffect } from "react";

const Hello: React.FC = () => {
  useEffect(() => {
    console.log("コンポーネントが表示されました");
  }, []);

  return <h1>こんにちは!</h1>;
};

export default Hello;
(画面に「こんにちは!」と表示され、開いた瞬間にコンソールに「コンポーネントが表示されました」と出力されます)

この場合、型を特に書かなくてもTypeScriptが自動的に判断してくれるので安全です。これを型推論といいます。

2. イベントや値を扱う場合の型安全

2. イベントや値を扱う場合の型安全
2. イベントや値を扱う場合の型安全

useEffect内でイベントや値を扱うときも、TypeScriptは自動で型を推論してくれます。ただし、非同期処理などを書くときには明示的に型を書くと安全になります。


import React, { useEffect, useState } from "react";

const Timer: React.FC = () => {
  const [count, setCount] = useState<number>(0);

  useEffect(() => {
    const id: NodeJS.Timeout = setInterval(() => {
      setCount((c) => c + 1);
    }, 1000);

    return () => clearInterval(id);
  }, []);

  return <h1>{count}秒経過</h1>;
};

export default Timer;
(画面に「1秒ごとに秒数が増えるカウンター」が表示されます)

ここで変数idに明示的にNodeJS.Timeoutという型を付けています。これは「タイマーID」を表す型で、明示しておくとエディタが補完してくれるので便利です。

3. 非同期処理とuseEffect

3. 非同期処理とuseEffect
3. 非同期処理とuseEffect

サーバーからデータを取得するときもuseEffectを使います。このとき、非同期処理を扱うのでPromise型が登場します。


import React, { useEffect, useState } from "react";

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

const UserList: React.FC = () => {
  const [users, setUsers] = useState<User[]>([]);

  useEffect(() => {
    const fetchData = async (): Promise<void> => {
      const response = await fetch("https://jsonplaceholder.typicode.com/users");
      const data: User[] = await response.json();
      setUsers(data);
    };
    fetchData();
  }, []);

  return (
    <ul>
      {users.map((user) => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  );
};

export default UserList;
(画面にAPIから取得したユーザーの名前がリスト表示されます)

ここではUserという型を定義し、useState<User[]>で型を指定しています。非同期関数fetchDataにも戻り値の型Promise<void>を付けています。

4. useEffectのクリーンアップ処理

4. useEffectのクリーンアップ処理
4. useEffectのクリーンアップ処理

useEffectの中でタイマーやイベントリスナーを登録した場合、不要になったときに解除しないとエラーやメモリリークの原因になります。そのため、戻り値に関数を返すことでクリーンアップできます。


import React, { useEffect } from "react";

const ResizeLogger: React.FC = () => {
  useEffect(() => {
    const handleResize = () => {
      console.log("ウィンドウサイズが変わりました");
    };

    window.addEventListener("resize", handleResize);

    return () => {
      window.removeEventListener("resize", handleResize);
    };
  }, []);

  return <h1>ウィンドウサイズを変えてみてください</h1>;
};

export default ResizeLogger;
(ウィンドウサイズを変更するとコンソールに「ウィンドウサイズが変わりました」と表示されます)

このクリーンアップ関数の戻り値は型で自動的に推論されるため、特別に書かなくても安全に使えます。

5. 型安全に使うポイントまとめ

5. 型安全に使うポイントまとめ
5. 型安全に使うポイントまとめ

初心者の方がTypeScriptでuseEffectを型安全に使うときのポイントを整理すると次の通りです。

  • useEffectそのものに型を書く必要は基本的にない(型推論される)
  • 非同期処理では戻り値の型をPromise<void>にする
  • タイマーやイベントリスナーは明示的に型を書くと補完が効いて便利
  • クリーンアップ関数は戻り値として自然に型付けされる

これらを意識するだけで、ReactとTypeScriptの組み合わせがより安全で安心な開発環境になります。

まとめ

まとめ
まとめ

ここまで、ReactTypeScriptを組み合わせて、useEffectを型安全に活用する方法について詳しく解説してきました。モダンなフロントエンド開発において、TypeScriptによる静的型付けは、バグを未然に防ぎ、チーム開発の効率を劇的に向上させる不可欠なツールです。特に、副作用(Side Effects)を管理するuseEffectフックでは、型の推論を活かしつつ、必要に応じて明示的な型定義を行うことが、堅牢なアプリケーション構築への近道となります。

TypeScriptでuseEffectを扱う際の重要ポイント

React初心者がTypeScriptを導入した際、どこに型を書くべきか迷うことが多いですが、useEffectに関しては「型推論」を最大限に活用するのがスマートな書き方です。以下の4点を意識するだけで、コードの品質は格段に上がります。

  • 依存関係配列(Dependency Array)の整合性: 配列内に指定する変数の型が正しく定義されていれば、TypeScriptがその変化を正確に追跡してくれます。
  • 非同期処理の定義方法: useEffect内で直接async関数を定義するのではなく、内部で一度名前付きの非同期関数を定義し、その戻り値をPromise<void>とすることで、意図しない戻り値によるエラーを防止できます。
  • クリーンアップ関数の役割: return () => { ... } という形式は、React内部の型定義(EffectCallback)によって保護されています。メモリリークを防ぐため、イベントリスナーの削除やタイマーのクリアは必須です。
  • 外部ライブラリとの連携: API通信などで外部のデータ構造を扱う際は、あらかじめinterfacetypeで型を定義し、useStateのジェネリクスに渡すことで、useEffect内でのデータ操作が劇的に楽になります。

実践的な型安全のサンプルコード

最後に、これまでの内容を統合した、より実戦に近いコード例を確認しましょう。ユーザーのオンライン状態を監視し、TypeScriptの機能をフル活用したコンポーネントの例です。


import React, { useState, useEffect } from "react";

// ユーザー情報の型定義
type UserStatus = {
  id: string;
  isOnline: boolean;
};

const StatusChecker: React.FC<{ userId: string }> = ({ userId }) => {
  const [status, setStatus] = useState<UserStatus | null>(null);

  useEffect(() => {
    // 非同期でのデータ取得シミュレーション
    const checkStatus = async (): Promise<void> => {
      try {
        // ダミーのAPIコールを想定
        const response = await fetch(`https://api.example.com/status/${userId}`);
        const data: UserStatus = await response.json();
        setStatus(data);
      } catch (error) {
        console.error("ステータス取得に失敗しました", error);
      }
    };

    checkStatus();

    // 1分ごとに更新するタイマーをセット
    const intervalId: NodeJS.Timeout = setInterval(() => {
      checkStatus();
    }, 60000);

    // クリーンアップ関数でタイマーを解除
    return () => clearInterval(intervalId);
  }, [userId]); // userIdが変更された時だけ再実行

  return (
    

ユーザーID: {userId}

ステータス: {status?.isOnline ? "オンライン" : "オフライン"}

); }; export default StatusChecker;
(画面には特定のユーザーIDと、そのオンライン状態が表示されます。コンポーネントが破棄されたり、別のユーザーIDが渡されたりすると、古いタイマーは自動的に破棄されます)

このように、ジェネリクスユニオン型UserStatus | null)を適切に使い分けることで、データの読み込み中やエラー時も含めた「状態」を安全に表現できます。 TypeScriptは決して開発を縛るものではなく、エディタの補完機能を最大限に引き出し、未来の自分やチームメンバーを助けるための「設計図」です。少しずつ慣れていき、快適なReact開発ライフを送りましょう!

先生と生徒の振り返り会話

生徒

「先生、今回のまとめでuseEffectとTypeScriptの関係がかなりクリアになりました!基本的にはTypeScriptの賢い推論に任せて、非同期処理や外部のデータ構造を扱うときだけ、自分でしっかり型を定義してあげればいいんですね。」

先生

「その通りです。すべてをガチガチに型指定しようとせず、TypeScriptが『何を助けてくれるのか』を理解するのが上達のコツですよ。特にクリーンアップ関数の話は、実際の開発現場でメモリリークを防ぐためにとても重要なんです。」

生徒

「確かに、クリーンアップを忘れてブラウザの動作が重くなるという話はよく聞きますもんね。あと、APIから取得するデータの型をtypeで定義しておくと、エディタでプロパティ名が自動補完されるのが本当に便利だと感じました!」

先生

「そうですね。タイピングミスも防げますし、何よりコードを読んだだけでどんなデータが流れてくるのか一目でわかります。今回のサンプルコードでも、status?.isOnline のようにオプショナルチェイニングを使うことで、nullの場合のクラッシュも防いでいますよ。」

生徒

「なるほど、TypeScriptの型ガードもしっかり効いているわけですね。最初はエラーが出るのが怖かったですけど、今はエラーが出るおかげでバグを未然に防げている安心感があります。」

先生

「素晴らしい成長ですね!その安心感こそがTypeScriptを使う最大のメリットです。次は、独自に作成したフック、いわゆるカスタムフックでuseEffectをどうカプセル化し、型を定義するかについても学んでいくと、さらにReactの世界が広がりますよ。」

生徒

「カスタムフックですか!どんどん難しくなりそうですが、型安全を武器にして挑戦してみます。先生、ありがとうございました!」

カテゴリの一覧へ
新着記事
New1
React
Reactコンポーネントの再利用と分割を完全マスター!初心者でもわかるコンポーネント設計
New2
React
ReactでAxiosインターセプターの使い方を完全ガイド!初心者でもわかるリクエストとレスポンスの処理方法
New3
React
JSXの書き方!初心者でもわかるReactタグと属性の基本ルール解説
New4
React
ReactとDockerを使った開発環境構築の基本を徹底解説!初心者でもわかるReactとDockerの連携方法
人気記事
No.1
Java&Spring記事人気No1
React
ReactでonChangeイベントを使ってフォーム入力値を管理する方法を初心者向けに解説
No.2
Java&Spring記事人気No2
React
ReactとTypeScriptの環境構築をやさしく解説!Viteとtsconfigの設定も丁寧に紹介
No.3
Java&Spring記事人気No3
React
Reactのイベントハンドリングのアンチパターンまとめ!初心者でもわかる注意点
No.4
Java&Spring記事人気No4
React
Reactのカスタムフックの作り方を完全ガイド!再利用可能なロジックを切り出す仕組み
No.5
Java&Spring記事人気No5
React
ReactでFetch APIのローディング状態を管理する方法|初心者にもわかる解説
No.6
Java&Spring記事人気No6
React
Reactでファイルアップロードを実装する方法を解説!Fetch APIで画像やPDFを送る仕組みを初心者向けに紹介
No.7
Java&Spring記事人気No7
React
ReactのuseStateとuseEffectでよくあるエラーと解決方法ガイド!初心者でもわかるReactフック
No.8
Java&Spring記事人気No8
React
create-react-appでReactプロジェクトを作成する手順を初心者向けに完全解説!