【第14回】使い回せる型の作り方|ジェネリクスの最小限(嫁子が教えるTS講座)

今回のゴール

前回(interface と type)まででデータの形は扱えるようになりました。今回は、その形をあとから差し込む書き方です。全体の流れは講座の目次へ。


嫁子: 「ジェネリクス」って名前で身構える人が多いんだけど、実物はもう第2部から見てるよ。

Promise って出てきたでしょ。あれの正式な姿は Promise<Response> なの。山かっこの中は「何が入って返ってくるか」。それだけの話だね。

今日は自分で書けなくていい。AIが書いたコードを見て固まらなくなれば、それで目標達成だよ。


① 山かっこは「中身の指定」

まず、すでに知っている書き方を並べ替えてみます。

const names: string[] = ["牛乳", "卵"];
const names2: Array<string> = ["牛乳", "卵"];   // 同じ意味

string[]Array<string> は同じものです。「配列」という入れ物に、「中身は文字列」と指定しています。

第8回のPromiseも同じ形をしています。

const res: Promise<Response> = fetch("https://example.com/data.json");

「待ったあとに Response が出てくる引換券」と読みます。中身が変われば指定も変わります。

async function getItems(): Promise<Item[]> {
  // Item の配列を返す非同期関数
}

嫁子: ここまで分かれば、実務で見る山かっこの9割は読めるよ。

入れ物の名前が前、中身の型が山かっこの中。Promise<Item[]> は「あとで Item の配列が出てくる」。それだけだね。


② なぜ必要なのか

「配列」という仕組みは、中身が何であっても同じように動きます。文字列でも数値でも Item でも、追加や取り出しのやり方は変わりません。

だからといって StringArrayNumberArrayItemArray と別々に用意していたら、際限がなくなります。

そこで入れ物だけを先に作り、中身は使うときに指定するという形になっています。これがジェネリクスです。

書き方 意味
Array<string> 文字列が入る配列
Promise<Item[]> あとで Item の配列が出てくる
Record<string, number> 文字列のキーに数値が対応する形

③ 自分で書くとしたら

読めれば十分と言いましたが、形だけ見ておきます。

function first<T>(items: T[]): T | undefined {
  return items[0];
}

<T> は「型を1つ受け取ります」という宣言です。T は使うときに決まります。

first(["牛乳", "卵"]);       // string | undefined が返る
first([250, 300]);          // number | undefined が返る

渡したものに応じて、戻り値の型が変わります。any を使えば同じことは書けますが、それだと前回の話の通りチェックが止まります。ジェネリクスは、チェックを効かせたまま使い回すための仕組みです。

戻り値が T | undefined なのは、空の配列を渡されたら何も無いからです。TypeScriptはそこまで込みで教えてくれます。

嫁子: T は Type の頭文字で、慣習みたいなものだよ。UV が続くこともある。

ここは意味を持たない記号だと思っていい。「何かの型が入る場所」ってだけだからね。


④ 第4部で必ず出てくる形

先に見ておくと、あとで楽になります。Reactでは状態を持つときにこう書きます。

const [name, setName] = useState<string>("");
const [items, setItems] = useState<Item[]>([]);

useState<Item[]>([]) は「空の配列から始めるけれど、中に入るのは Item だよ」という宣言です。

第12回で「空の配列から始めるときは型を書く」と言ったのと同じ理由で、空だと何が入る予定なのか判断できないからです。

嫁子: これ、第4部で必ずつまずくところなの。空の配列に型を書き忘れると、あとから何を入れてもエラーになるんだよ。

never[](何も入れられない配列)と判断されてしまうからね。「空から始めるときは中身を書く」だけ覚えておいて。


つまずきポイント

山かっこは比較演算子ではありません。a < b< と見た目は同じですが、型の文脈では別物です。慣れるまでは「型の名前のうしろの <> は中身の指定」と覚えてください。

自分で <T> を書く場面は当分きません。AIが書いてきたときに読めれば十分です。書く必要が出るのは、複数の型で共通して使う関数を自作するときです。


今回のまとめ


次にやること

次回はtsconfig と strictです。どこまで厳しく見張らせるかの設定と、TypeScriptをJavaScriptに変換する手順を扱います。第16回で買い物メモを書き換える前の、最後の準備になります。

今回の宿題:ありません。今日は読み流して構いません。

嫁子: 宿題が無いのは、今日の内容は単体で練習しても身につかないからなの。

実際にReactを触って useState<Item[]>([]) を書く場面が来たとき、「ああ、あれか」となればいい。先に一度見ておいた、という状態を作るのが今日の目的だよ。