【第14回】使い回せる型の作り方|ジェネリクスの最小限(嫁子が教えるTS講座)
今回のゴール
Promise<Item[]>のような山かっこが何を指すか分かる- 中身の型を後から指定する、という考え方が分かる
- 今回は書けなくていい。読めれば十分
前回(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 でも、追加や取り出しのやり方は変わりません。
だからといって StringArray、NumberArray、ItemArray と別々に用意していたら、際限がなくなります。
そこで入れ物だけを先に作り、中身は使うときに指定するという形になっています。これがジェネリクスです。
| 書き方 | 意味 |
|---|---|
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 の頭文字で、慣習みたいなものだよ。UやVが続くこともある。ここは意味を持たない記号だと思っていい。「何かの型が入る場所」ってだけだからね。
④ 第4部で必ず出てくる形
先に見ておくと、あとで楽になります。Reactでは状態を持つときにこう書きます。
const [name, setName] = useState<string>("");
const [items, setItems] = useState<Item[]>([]);
useState<Item[]>([]) は「空の配列から始めるけれど、中に入るのは Item だよ」という宣言です。
第12回で「空の配列から始めるときは型を書く」と言ったのと同じ理由で、空だと何が入る予定なのか判断できないからです。
嫁子: これ、第4部で必ずつまずくところなの。空の配列に型を書き忘れると、あとから何を入れてもエラーになるんだよ。
never[](何も入れられない配列)と判断されてしまうからね。「空から始めるときは中身を書く」だけ覚えておいて。
つまずきポイント
山かっこは比較演算子ではありません。a < b の < と見た目は同じですが、型の文脈では別物です。慣れるまでは「型の名前のうしろの <> は中身の指定」と覚えてください。
自分で <T> を書く場面は当分きません。AIが書いてきたときに読めれば十分です。書く必要が出るのは、複数の型で共通して使う関数を自作するときです。
今回のまとめ
- 山かっこは入れ物の中身の指定。
Array<string>はstring[]と同じ Promise<Item[]>は「あとで Item の配列が出てくる」<T>は「型を受け取る」という宣言。anyと違い、チェックを効かせたまま使い回せる- 空の配列から始めるときは中身の型を書く(
useState<Item[]>([])) - 今回は書けなくていい。読めれば目的は足りている
次にやること
次回はtsconfig と strictです。どこまで厳しく見張らせるかの設定と、TypeScriptをJavaScriptに変換する手順を扱います。第16回で買い物メモを書き換える前の、最後の準備になります。
今回の宿題:ありません。今日は読み流して構いません。
嫁子: 宿題が無いのは、今日の内容は単体で練習しても身につかないからなの。
実際にReactを触って
useState<Item[]>([])を書く場面が来たとき、「ああ、あれか」となればいい。先に一度見ておいた、という状態を作るのが今日の目的だよ。