第135章:カスタムフックの「戻り値」に型を付ける!
「カスタムフックって便利そうだけど、戻り値の型ってどう書けばいいの…?😇」 この章では、そこをスッキリさせます!
1️⃣ この章でできるようになること
この章のゴールはこんな感じです👇
- カスタムフックに 「戻り値の型」 をしっかり付けられる 🎯
typeで「戻り値専用の型」を作れる- 「配列(タプル)で返す型」と「オブジェクトで返す型」のイメージがつかめる
- VS Code がいい感じに補完してくれて、コーディングがラクになる ✨
2️⃣ カスタムフックの「戻り値」ってそもそも何? 🤔
カスタムフックは、ざっくり言うと
「中のごちゃごちゃしたロジックを隠して、 コンポーネント側には 使いやすいセットだけ渡す 関数」
でしたよね 🧠
例えば前の章で作った useToggle なら、
-
中で
useStateとかsetValueみたいな処理をしておいて -
コンポーネントには
- 今の状態(
boolean) - それを切り替える関数(
() => void)
- 今の状態(
だけを渡してあげる、みたいなイメージです。
つまり、カスタムフックにはいつも
- 「受け取る引数の型」
- 「返す値(戻り値)の型」
この2つがセットで存在します ✅ この章では特に 「返す方(戻り値)の型」 にフォーカスします。
3️⃣ まずは「型なし」カスタムフックを見てみよう 👀
型を付ける前の useToggle を、ざっくりこんな感じだとします。
// useToggle.ts
import { useState } from "react";
export function useToggle(initialValue = false) {
const [value, setValue] = useState(initialValue);
const toggle = () => {
setValue((prev) => !prev);
};
return [value, toggle];
}
これでも動きはしますが…
initialValueの型もreturnで返している配列の中身の型も
TypeScript がなんとな〜く推論しているだけの状態です。
VS Code で使う側を書くときに、
- 「
valueは boolean だっけ? string だっけ?」 - 「
toggleの引数って必要だったっけ?」
みたいなのが、パッと見で分かりにくいんですよね 🥲
4️⃣ 戻り値の型を type で用意してあげよう ✏️
そこで登場するのが「戻り値専用の型」です。
🧩 ステップ1:戻り値の型だけを先に作る
今回の useToggle の戻り値は、
boolean(今の状態)()→voidな関数(切り替え)
の2つを 配列で返している ので、こんな type を用意します👇
// useToggle.ts
import { useState } from "react";
// ✅ 戻り値の型だけを先に定義しておく
type UseToggleResult = [boolean, () => void];
[boolean, () => void] という書き方は、
「長さ2のタプル(順番と型が決まった配列)」 を意味します。
- 1番目:
boolean - 2番目:
() => void(引数なしで何も返さない関数)
という決まりになります 📦
🧩 ステップ2:関数の戻り値の型として使う
さっき定義した UseToggleResult を、
カスタムフックの戻り値の型としてくっつけます。
// useToggle.ts
import { useState } from "react";
type UseToggleResult = [boolean, () => void];
export function useToggle(initialValue: boolean = false): UseToggleResult {
const [value, setValue] = useState(initialValue);
const toggle = () => {
setValue((prev) => !prev);
};
return [value, toggle];
}
ポイントはここです👇
-
initialValue: boolean = false- 引数にもちゃんと
booleanを付ける
- 引数にもちゃんと
-
): UseToggleResult { ... })の後ろに 戻り値の型 を書く
これで、
- 「
useToggleを呼ぶと、必ず[boolean, () => void]を返すんだな〜」 - というのが、コードを見ただけで一瞬で伝わるようになります ✨
5️⃣ 使う側でのメリット 💻
次に、この useToggle をコンポーネント側から使ってみます。
// ToggleExample.tsx
import { useToggle } from "./useToggle";
export function ToggleExample() {
const [isOpen, toggleIsOpen] = useToggle(false);
return (
<div>
<button onClick={toggleIsOpen}>
{isOpen ? "閉じる" : "開く"}
</button>
{isOpen && <p>開いてます〜✨</p>}
</div>
);
}
ここで VS Code の上にマウスを乗せてみると…
isOpen→booleanと表示されるtoggleIsOpen→() => voidと表示される
などなど、型情報がちゃんと見えるようになります 👀
さらに、
-
toggleIsOpen(123)みたいに変な引数を渡そうとすると- 「引数いらないよ!」と TypeScript が怒ってくれる
-
isOpen.toUpperCase()みたいに文字列メソッドを呼ぼうとすると- 「これは boolean なのでそんなメソッドないよ!」と怒ってくれる
という感じで、バグをかなり早い段階で止めてくれるようになります 🚨✨
6️⃣ オブジェクトで返すパターンの型 🧺
今までは「配列(タプル)」で返す例でしたが、 カスタムフックの戻り値は オブジェクトでもOK です。
🌟 オブジェクト版 useToggle
// useToggleObject.ts
import { useState } from "react";
type UseToggleObjectResult = {
value: boolean;
toggle: () => void;
};
export function useToggleObject(
initialValue: boolean = false
): UseToggleObjectResult {
const [value, setValue] = useState(initialValue);
const toggle = () => {
setValue((prev) => !prev);
};
return { value, toggle };
}
使う側はこんな感じ👇
// ToggleObjectExample.tsx
import { useToggleObject } from "./useToggleObject";
export function ToggleObjectExample() {
const { value: isOpen, toggle } = useToggleObject(false);
return (
<div>
<button onClick={toggle}>
{isOpen ? "閉じる" : "開く"}
</button>
{isOpen && <p>オブジェクト版も動いてます〜🎉</p>}
</div>
);
}
📝 「タプル」vs「オブジェクト」どっちがいいの?
ざっくりした目安はこんな感じです👇
-
✅ タプルで返すとき
- 中身が2〜3個くらい
- 使う側で
[value, toggle]みたいに「順番」で扱うのが自然なとき
-
✅ オブジェクトで返すとき
- 返したいものが多い(4つ以上とか)
value,loading,errorみたいに「名前」で扱いたいとき
どちらを選んでもOKですが、
- 「型を付けておく」こと自体がめちゃくちゃ大事 💎
typeで戻り値の型を分けておくと、あとから戻り値を増やしたりするときも楽
というメリットがあります。
7️⃣ カスタムフックと戻り値の型の関係を図でイメージ 🧠✨
カスタムフックのイメージを、図でサクッと見てみましょう。
- コンポーネントは
useToggle()を呼ぶだけ - 中のロジックは全部カスタムフックの中
- コンポーネントは 「UseToggleResult 型のセット」 だけを受け取る
という流れになっています 💫
8️⃣ ミニ演習 🧪 やってみよう!
ここで、ちょっとだけ手を動かしてみましょう ✍️
🔰 演習1:自分の useToggle に戻り値の型を付ける
-
前の章で作った
useToggleを開く -
ファイルの上の方に、こんな
typeを追加する- タプル版なら:
type UseToggleResult = [boolean, () => void];- オブジェクト版なら:
type UseToggleResult = {
value: boolean;
toggle: () => void;
}; -
関数の定義に戻り値の型をつける
export function useToggle(initialValue: boolean = false): UseToggleResult {
// ...
} -
コンポーネント側で、マウスホバーして型が見えるかチェックしてみる 👀
🔰 演習2:「戻り値の型」を自分で考えてみる
次の章では useWindowSize を作る予定でした。
一足先に「戻り値の型」だけ考えてみましょう ✨
-
どんな情報を返したい?
- 例:
width,height
- 例:
-
配列で返す? オブジェクトで返す?
たとえば、オブジェクトで返すならこんな type になりそうです👇
type UseWindowSizeResult = {
width: number;
height: number;
};
「どんな情報を、どんな形でコンポーネントに渡したいか?」 を考えるのが、戻り値の型設計の第一歩です 💡
9️⃣ まとめ 🎀
この章で学んだポイントをおさらいします 👇
-
カスタムフックには「引数の型」だけでなく 「戻り値の型」 も超大事
-
戻り値の型は
typeで先に定義しておくとスッキリ ✨- 例:
type UseToggleResult = [boolean, () => void];
- 例:
-
戻り値は
- 少ないなら「タプル(配列)」でもOK
- 多くなってきたら「オブジェクト」が読みやすい
-
型をつけることで
- VS Code の補完が賢くなる
- 間違った使い方を TypeScript が止めてくれる
次の章では、実際に useWindowSize などの 実用カスタムフック を作りながら、
今学んだ「戻り値の型」をどんどん使っていきますよ〜 📏📱✨
おつかれさまでした!🍵💖