フックに型を付ける
戻り値の型は、フックの取扱説明書
useItems は items と loading と error を返します。型を書かないままだと、使う側にはこう見えます。
const result = useItems("shoes");
result.itmes.map(...) // 打ち間違いに誰も気付かない戻り値に any を付けているのも同じです。any は「何でもある」ではなく「検査をやめる」という意味なので、存在しない項目を書いても通ってしまいます。フックの戻り値の型は、使う人が読む唯一の説明書です。
型に名前を付けて返す
型を独立させ、関数の戻り値として書きます。
export type UseItemsResult = {
items: Item[];
loading: boolean;
error: string | null;
};
export function useItems(category: string): UseItemsResult {
...
return { items, loading, error };
}こう書くと3つの得があります。
- 使う側で
itemsと打った時点で候補が出る。綴りを間違えたらその場で赤くなる - 返し忘れると useItems 側が怒られる。使う側で気付くより早い
- 型に名前が付くので、他のファイルからも
UseItemsResultとして読める
error の型は string ではなく string | null
エラーが無いときは何も無い、という状態を型に書きます。string | null にしておくと、使う側は if (error) で分けるまで中身を文字として扱えません。「まだ無い」を型で表しておくと、無いときの分岐を書き忘れられなくなります。
配列で返すか、オブジェクトで返すか
useState は [value, setValue] という配列を返します。2つで、順番が決まっていて、名前を呼ぶ側が自由に決めたいからです。一方カスタムフックは3つ以上を返すことが多く、順番で覚えるのは無理があります。3つ以上を返すならオブジェクトにすると考えて構いません。
演習
useItems の戻り値に型を付け、使う側で loading と error を出し分けます。