TypeScriptカスタムHookに型をつける方法を解説!再利用性を高めるフロントエンド開発
生徒
「Reactで便利な機能を使い回したいのですが、TypeScriptでカスタムHookを作るにはどうすればいいですか?」
先生
「カスタムHookにしっかり型をつけることで、どこでも安全に再利用できるようになりますよ。」
生徒
「型をつけるのは難しそうですが、初心者でもできますか?」
先生
「大丈夫です!基本的なルールさえ覚えれば、バグの少ない便利な部品が作れます。一緒に見ていきましょう!」
1. カスタムHookとは何かを学ぼう
カスタムHook(カスタムフック)とは、React(リアクト)という道具を使ってWebサイトを作るときに、「よく使う便利な機能」を一つの部品としてまとめたものです。例えば、文字を入力する処理や、インターネットからデータを読み込む処理などは、色々な画面で何度も使いますよね。これらを毎回書くのは大変ですし、間違いのもとになります。そこで、機能をひとまとめにして「魔法の道具」のように呼び出せるようにしたのがカスタムHookです。
TypeScript(タイプスクリプト)を使う理由は、この魔法の道具に「使い方説明書」を付けるためです。このデータは数字ですよ、この文字は書き換えられませんよ、といったルールを型(かた)として決めておくことで、パソコンが間違いを教えてくれるようになります。プログラミングが初めての方でも、型があるおかげで安心してコードを書くことができるのです。
2. なぜ型をつけることが重要なのか
型をつける最大のメリットは、「再利用性」と「安全性」が高まることです。再利用性とは、一度作った部品を別の場所でも簡単に使える性質のことです。もし型がついていないと、その部品が何を返してくれるのか、どんな情報を渡せばいいのかが分からなくなり、使うのが怖くなってしまいます。しかし、TypeScriptで型を明示しておけば、エディタ(プログラムを書くソフト)が「ここにはこの情報を入れてください」と案内してくれます。
また、Next.js(ネクストジェーエス)のような最新の枠組みで開発する場合、複数のエンジニアで協力して作ることが多いです。型があることで、他の人が作った機能でも使い方が一目で分かり、勘違いによるミスを劇的に減らすことができます。これは、初心者の方がプログラミングを学ぶ上でも非常に助けになる機能です。
3. カウンター機能を作る簡単な例
まずは、数字を増やしたり減らしたりするシンプルなカウンターの機能を作ってみましょう。ここでは、現在の数字の状態と、それを増やすための命令をセットにして返します。TypeScriptでは、戻り値(返ってくる値)に型を指定することが大切です。
import { useState } from "react";
// カスタムHookの定義
// number型の値を初期値として受け取ります
export const useCounter = (initialValue: number) => {
const [count, setCount] = useState<number>(initialValue);
const increment = () => setCount(count + 1);
const decrement = () => setCount(count - 1);
// 返り値に型を意識させるため、配列の形(タプル)で返します
return { count, increment, decrement };
};
このコードでは、initialValue: numberと書くことで、最初に渡す値は「数字」でなければならないというルールを作っています。もし間違えて文字を渡そうとすると、TypeScriptがすぐにエラーとして教えてくれます。これが型の力です。
4. 入力フォームの状態管理を共通化する
次に、Webサイトの問い合わせフォームなどでよく使う、文字入力の状態を管理するカスタムHookを作ってみましょう。ユーザーが文字を打ち込むたびに、その内容を保存する処理です。ここでは、文字を扱うのでstring(ストリング)という型を使います。
import { useState, ChangeEvent } from "react";
export const useInput = (initialText: string) => {
const [value, setValue] = useState<string>(initialText);
// 入力内容が変わったときに実行される関数
const onChange = (event: ChangeEvent<HTMLInputElement>) => {
setValue(event.target.value);
};
return { value, onChange };
};
ここで出てくるChangeEvent<HTMLInputElement>は少し難しく見えるかもしれませんが、「入力欄の内容が変わったという出来事」を表す専用の型です。このように、Reactが用意してくれている型を組み合わせることで、より正確なプログラムを書くことができます。これにより、どの入力欄でもこのHookを使い回せるようになります。
5. ジェネリクスを使った高度な再利用
再利用性を極限まで高める方法として「ジェネリクス」という技術があります。これは、「使うときに型を決める」という仕組みです。例えば、リストの中に情報を保存する機能を作るとき、それが数字のリストなのか、文字のリストなのかを、使う側で自由に決められるようになります。アルファベットのTなどを使って表現することが一般的です。
import { useState } from "react";
// Tは「使うときに決める型」という意味です
export function useList<T>(initialList: T[]) {
const [list, setList] = useState<T[]>(initialList);
const addItem = (item: T) => {
setList([...list, item]);
};
return { list, addItem };
}
このuseListを使えば、あるときは「名前(文字)のリスト」を管理し、別のときは「年齢(数字)のリスト」を管理するといった使い分けが、これ一つのコードで可能になります。初心者の方にとっては少し応用編ですが、非常に強力な武器になります。
6. Booleanを切り替えるシンプルなフック
Webサイトでは「メニューを開く・閉じる」や「ボタンを押せる・押せない」といった、二つの状態(オンとオフ)を切り替える場面が非常に多いです。これをプログラミングではboolean(ブーリアン)と呼びます。真か偽か、という意味です。これを管理する専用のHookを作ると、コードがスッキリします。
import { useState } from "react";
export const useToggle = (initialState: boolean = false) => {
const [state, setState] = useState<boolean>(initialState);
// 状態を反対にする関数
const toggle = () => setState((prev) => !prev);
return [state, toggle] as const;
};
最後のas constという書き方は、「この配列の中身の順番や役割は決まっていますよ」とTypeScriptに伝えるためのおまじないです。これを入れることで、使う側で型が正確に認識され、非常に使い勝手の良い部品になります。例えば、モーダルウィンドウの表示・非表示の制御などにピッタリです。
7. カスタムHookを使う側の書き方を確認しよう
作ったカスタムHookを実際にどのように画面(コンポーネント)で使うのかを見てみましょう。ここでは、先ほど作ったuseCounterを使って、画面に数字を表示し、ボタンで増やす仕組みを作ります。HTMLのような見た目を書く部分と、プログラムの動きを組み合わせます。
import React from "react";
import { useCounter } from "./useCounter";
export const CounterDisplay = () => {
// カスタムHookを呼び出して機能を取り出す
const { count, increment, decrement } = useCounter(0);
return (
<div className="p-4 border rounded">
<h2>現在の数字: {count}</h2>
<button onClick={increment} className="btn btn-primary me-2">増やす</button>
<button onClick={decrement} className="btn btn-secondary">減らす</button>
</div>
);
};
このように、複雑な計算や状態の変化はカスタムHookの中に隠されているため、画面を作るコードはとても短く、読みやすくなります。これが「部品化」の素晴らしいところです。もしバグが見つかっても、カスタムHookの中身だけを直せば、それを使っているすべての画面が一度に修正されます。
8. TypeScriptのエラーを防ぐコツ
TypeScriptを使い始めると、赤い波線(エラー)が出て困ることがあるかもしれません。しかし、それは意地悪ではなく「このまま動かすと壊れますよ」という親切な警告です。カスタムHookを自作するときは、特に「引数(渡す値)」と「戻り値(返ってくる値)」の型を意識しましょう。
初心者のうちは、エディタが提案してくれるヒントをよく読む癖をつけるのが上達の近道です。また、最初は型を細かく決めすぎず、基本的なnumber、string、booleanから使い始めてみてください。徐々に慣れてくると、複雑な仕組みもパズルのように組み合わせて作れるようになり、プログラミングがどんどん楽しくなっていくはずです。