カテゴリ: TypeScript 更新日: 2026/05/25

TypeScriptでuseRefとuseContextの型定義をマスター!React開発の初心者向け完全ガイド

TypeScriptでuseRef/useContextの型を定義する方法
TypeScriptでuseRef/useContextの型を定義する方法

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

生徒

「Reactで便利なuseRefやuseContextを使いたいのですが、TypeScriptだと型のエラーが出てしまって難しいです。」

先生

「そうですね。TypeScriptでは、そのデータが何なのかを事前に教えてあげる『型定義』がとても大切になります。」

生徒

「初心者でも失敗しない、正しい型の書き方を教えてもらえますか?」

先生

「もちろんです!今回は、初心者の方が特につまずきやすいポイントを丁寧に解説していきますね。」

1. TypeScriptとReactのフックについて学ぼう

1. TypeScriptとReactのフックについて学ぼう
1. TypeScriptとReactのフックについて学ぼう

プログラミングを始めたばかりの方にとって、「型」という言葉は少し難しく感じるかもしれません。型とは、簡単に言うと「その箱(変数)の中に何を入れるかのルール」のことです。TypeScriptを使う最大のメリットは、このルールをあらかじめ決めておくことで、間違ったものを入れようとしたときにパソコンが「それは違いますよ!」と教えてくれる点にあります。

Reactという道具を使って画面を作る際によく使われるのが「フック」と呼ばれる機能です。その中でも、画面上の部品を直接操作するためのuseRefや、複数の部品でデータを共有するためのuseContextは非常に強力です。これらをTypeScriptで使うとき、どのようなルール(型)を適用すればよいのか、基本からじっくり学んでいきましょう。

2. useRefの基本的な役割と型定義の重要性

2. useRefの基本的な役割と型定義の重要性
2. useRefの基本的な役割と型定義の重要性

useRefは、主に二つの役割を持っています。一つは、入力フォームに自動でカーソルを合わせるなど、HTMLの要素を直接触りたいとき。もう一つは、画面を書き換えずに値を保存しておきたいときです。パソコンに詳しくない方向けに例えると、useRefは「特定の場所に貼り付けた付箋」や「指差し確認のための目印」のようなものです。

TypeScriptでは、この付箋が「どの種類の部品を指しているのか」を正確に指定する必要があります。例えば、文字を入力する場所なのか、ボタンなのか、それともただの数字を覚えているだけなのかを区別します。これを正しく行わないと、プログラムは「そこにあるのが何かわからないので、操作させられません」と機嫌を損ねてしまいます。まずは、一番よく使う「HTML要素を操作する場合」の書き方を見てみましょう。

3. useRefでHTML要素に型を付ける方法

3. useRefでHTML要素に型を付ける方法
3. useRefでHTML要素に型を付ける方法

例えば、ボタンをクリックしたときに入力欄に色を付けたり、文字を自動で入力したりしたい場合があります。このとき、useRefの中身が「HTMLの入力欄(input要素)」であることを教える必要があります。TypeScriptには、あらかじめHTMLInputElementHTMLButtonElementといった名前の型が用意されています。

以下のコードは、入力フォーム(input)を操作するための基本的な型定義の例です。初心者のうちは、nullで初期化することをセットで覚えておくと、エラーを防ぎやすくなります。これは、画面が表示される瞬間までは、まだその部品が準備できていない可能性があるためです。


import React, { useRef } from 'react';

const TextInputFocus = () => {
    // HTMLのinput要素を指すための型を指定します
    // 初期値は「まだ何もない」という意味のnullを入れます
    const inputRef = useRef<HTMLInputElement>(null);

    const handleClick = () => {
        // currentの中身があるか確認してから操作します
        if (inputRef.current) {
            inputRef.current.focus();
            console.log("入力欄にカーソルを合わせました");
        }
    };

    return (
        
<input ref={inputRef} type="text" /> <button onClick={handleClick}>フォーカスを当てる</button>
); };

このように、<HTMLInputElement>のように不等号で囲って型を書く方法を「ジェネリクス」と呼びます。これは「この道具(useRef)を、HTMLInputElement専用として使います」という宣言になります。

4. 値の保持にuseRefを使う場合の型定義

4. 値の保持にuseRefを使う場合の型定義
4. 値の保持にuseRefを使う場合の型定義

useRefは、画面の見た目に関係のないデータをこっそり持っておくのにも使えます。例えば、タイマーのIDや、前の画面の状態を覚えておくときなどです。この場合は、操作したいデータの種類(数値ならnumber、文字ならstring)を指定します。HTML要素ではないので、初期値に具体的な数字を入れることが多いです。


import React, { useRef } from 'react';

const CounterRef = () => {
    // 数字(number型)を保存するためのuseRefです
    // 初期値として「0」を入れます
    const countRef = useRef<number>(0);

    const increment = () => {
        countRef.current += 1;
        console.log("現在の値は: " + countRef.current);
    };

    return (
        
<p>コンソールで値を確認してください</p> <button onClick={increment}>カウントアップ</button>
); };

実行結果は以下のようになります。ボタンを押しても画面の数字は変わりませんが、プログラムの内部ではしっかりと数字が増えていきます。


現在の値は: 1
現在の値は: 2
現在の値は: 3

5. useContextとは?データのバケツリレーを防ぐ魔法

5. useContextとは?データのバケツリレーを防ぐ魔法
5. useContextとは?データのバケツリレーを防ぐ魔法

次にuseContextについて解説します。通常、Reactでは親から子、子から孫へとデータを手渡ししていきます。これを「プロップス(Props)」と呼びますが、あまりに階層が深いと、途中の部品が自分では使わないデータをただ渡すだけになってしまいます。これを「バケツリレー」と呼び、プログラムが複雑になる原因となります。

useContextは、このバケツリレーを飛ばして、必要なデータをどこからでも直接取り出せるようにする仕組みです。いわば、家の中のどこにいてもアクセスできる「共有の冷蔵庫」のようなものです。しかし、冷蔵庫に何が入っているか分からないと困るように、TypeScriptでも「この共有データには何が入っているのか」を明確に定義しなければなりません。

6. useContextの型定義:Contextの作成と提供

6. useContextの型定義:Contextの作成と提供
6. useContextの型定義:Contextの作成と提供

useContextを使うには、まず「どんなデータを共有するか」という設計図を作ることから始めます。これを「コンテキストの作成」と言います。初心者が特につまずくのは、初期値の設定です。最初はデータが空っぽであることが多いため、型定義には「データの形、または未定義(undefined)」といった柔軟性を持たせることが一般的です。

以下の例では、ユーザーの名前をアプリ全体で共有するための型定義を行っています。interfaceという言葉を使って、データの構造に名前を付けています。これは「このデータはこういう形をしていますよ」という証明書のようなものです。


import React, { createContext, useContext } from 'react';

// 1. 共有したいデータの形を定義します
interface UserConfig {
    name: string;
    isLoggedIn: boolean;
}

// 2. コンテキストを作成します。最初はデータがないかもしれないので
// UserConfig型か、もしくはundefinedが許容されるようにします
const UserContext = createContext<UserConfig | undefined>(undefined);

const UserDisplay = () => {
    // 3. データを呼び出します
    const user = useContext(UserContext);

    // データがなかった場合の処理を必ず書きます(TypeScriptのルール)
    if (!user) {
        return <p>ログインしていません</p>;
    }

    return (
        <div>
            <p>こんにちは、{user.name}さん!</p>
        </div>
    );
};

7. useContextで関数を共有する場合のテクニック

7. useContextで関数を共有する場合のテクニック
7. useContextで関数を共有する場合のテクニック

データだけでなく、データを書き換えるための「関数(機能)」を共有することもよくあります。例えば、ダークモードへの切り替えスイッチなどです。関数を型定義するときは、引数(入れるもの)と戻り値(返ってくるもの)を指定します。何も返さない関数の場合は、void(ボイド)という特殊な言葉を使います。これは「空っぽ」という意味です。


import React, { createContext, useState, ReactNode } from 'react';

// テーマの種類と、それを変えるための関数の形を決めます
interface ThemeContextType {
    theme: string;
    toggleTheme: () => void;
}

// コンテキストを作成
export const ThemeContext = createContext<ThemeContextType | undefined>(undefined);

// プロバイダーという「データを提供する親」を作ります
export const ThemeProvider = ({ children }: { children: ReactNode }) => {
    const [theme, setTheme] = useState("light");

    const toggleTheme = () => {
        setTheme((prev) => (prev === "light" ? "dark" : "light"));
    };

    return (
        <ThemeContext.Provider value={{ theme, toggleTheme }}>
            {children}
        </ThemeContext.Provider>
    );
};

ここで出てきたReactNodeは、Reactが画面に表示できるあらゆるもの(文字、タグ、他の部品など)を指す非常に便利な型です。これを使うことで、どんな部品でも包み込むことができるようになります。

8. エラーを防ぐ!カスタムフックでの安全な取り出し方

8. エラーを防ぐ!カスタムフックでの安全な取り出し方
8. エラーを防ぐ!カスタムフックでの安全な取り出し方

useContextを直接使うと、先ほどのコードのように毎回「データが空(undefined)ではないか」を確認しなければなりません。これは少し面倒ですし、忘れるとエラーの原因になります。そこで、開発現場では「カスタムフック」という自分専用の道具を作って、安全にデータを取り出す工夫をします。

以下のコードは、データが見つからない場合に分かりやすいエラーメッセージを出してくれる、とても親切な仕組みです。これを用意しておくだけで、開発の効率がぐんと上がります。


import { useContext } from 'react';
import { ThemeContext } from './ThemeProvider';

// 独自の「useTheme」というフックを作ります
export const useTheme = () => {
    const context = useContext(ThemeContext);
    
    // もしThemeProviderの外で使おうとしたらエラーを出します
    if (context === undefined) {
        throw new Error("useThemeはThemeProviderの中で使ってください");
    }
    
    return context;
};

このように、「もしもの時」の処理をあらかじめ書いておくのが、良いプログラムを作るコツです。パソコンに慣れていない方でも、このパターンを覚えておけば、複雑なアプリ開発でも迷わずに進めるようになります。TypeScriptは厳しい先生のように思えるかもしれませんが、実は私たちがミスをしないようにずっと見守ってくれている優しいガイドなのです。

カテゴリの一覧へ
新着記事
New1
TypeScript
TypeScriptの関数に型をつける方法(引数・戻り値)を初心者向けに徹底解説!
New2
TypeScript
TypeScriptの始め方:開発環境の構築手順【初心者向け】
New3
TypeScript
TypeScriptでExpressのミドルウェアを型安全に定義する方法!バックエンド開発の初心者向け解説
New4
JavaScript
JavaScriptのfilterメソッドで条件に合う要素を抽出する方法
人気記事
No.1
Java&Spring記事人気No1
JavaScript
JavaScriptでフォームの値を取得する方法を徹底解説!valueプロパティの使い道
No.2
Java&Spring記事人気No2
JavaScript
JavaScriptでHTML5バリデーションAPIを使いこなす!初心者でもわかるフォーム入力チェック
No.3
Java&Spring記事人気No3
TypeScript
TypeScript学習におすすめの無料教材・リファレンスサイト【初心者向け】
No.4
Java&Spring記事人気No4
TypeScript
TypeScriptでコメントを書く正しい書き方と使い分け【初心者向けにやさしく解説】
No.5
Java&Spring記事人気No5
JavaScript
JavaScriptで要素を削除する方法(removeChild, removeなど)
No.6
Java&Spring記事人気No6
JavaScript
JavaScriptのインストール方法まとめ!Windows・Mac・Linux別にステップ解説
No.7
Java&Spring記事人気No7
JavaScript
JavaScriptの配列操作でよくあるエラーとその解決法まとめ
No.8
Java&Spring記事人気No8
JavaScript
JavaScriptの現在日時を取得する方法を完全ガイド!初心者でもわかるDate.now()とnew Date()