TypeScript入門

なぜジェネリクスか

同じ処理を、型が違うだけで書き直している

作品タイトルの配列から先頭を取り出す関数です。

function firstTitle(items: string[]): string { return items[0]; }

作品 ID の配列でも同じことをしたくなりました。中身は 1 文字も違わないのに、型が違うのでもう 1 本必要になります。

function firstId(items: number[]): number { return items[0]; }

boolean[] でも、第4章で作った Work[] でも同じです。扱いたい型が増えるたびに、まったく同じ処理が増えていきます。

any でまとめると、検査が消える

いちばん手軽なまとめ方が any です。

function first(items: any[]): any { return items[0]; }

1 本で済みます。ただし戻り値の型が any になります。

const titles = ["プロフィールサイト", "自己紹介カード"]; const title = first(titles); title.toUpperCase(); // 通る title.toFixed(2); // これも通ってしまう

toFixed は数値のメソッドです。title の正体は文字列なので、実行すると title.toFixed is not a function で落ちます。それでもエディタは何も言いません。第2章で見たとおり、any を書いた場所から先は検査が止まるからです。

汎用にした代償として、型の情報を捨ててしまったわけです。

欲しいのは「呼ぶときに決まる型」

本当に必要なのは、string でも number でもない、呼び出すたびに中身が入れ替わる型です。それを書けるようにするしくみがジェネリクスです。

function first<T>(items: T[]): T { return items[0]; } const title = first(titles); // string に決まる const id = first([1, 2, 3]); // number に決まる

T は型を入れる箱です。関数は 1 本のまま、返ってきた値の型は呼び出しごとに決まります。だから title.toFixed(2) は、実行する前にエラーになります。

手を動かす

この章では、この T を自分で書けるようにしていきます。まずはエディタで any 版の first を書き、返ってきた値に存在しないメソッドを呼んでも何も言われないことを確かめてください。次のレッスンで、同じ関数を型引数で書き直します。

生田 陸人
ゆめさくエンジニア / 現役ソフトウェアエンジニア
編集 LuaGate編集部