TypeScriptのジェネリクスとは
TypeScriptのジェネリクスとは、型を後から指定できる仕組みです。同じ処理を複数の型で使い回せるため、コードの重複を減らしながら型安全性を保てます。


この記事では、TypeScript(Generics)のジェネリクスについて、基本の書き方からany型との違い、実務での使用例、よくあるエラーまで、JavaScript経験者向けに整理します。まずは基本をまとめた記事も参考にしてください。
ジェネリクスが必要な理由
ジェネリクスの必要性を理解するために、あえてジェネリクスを使わない例から見てみます。
function identity(value: string): string {
return value;
}
// number型を渡したい場合、同じような関数をもう一つ書く必要がある
function identityNumber(value: number): number {
return value;
}「値をそのまま返すだけ」の関数なのに、型ごとに同じ処理を何度も書くのは無駄です。JavaScriptなら型を気にせず1つの関数で済んでいたはずの処理が、TypeScriptだと型の数だけ関数が増えてしまう、というのが最初にジェネリクスの必要性を感じた瞬間でした。
<T>とは?基本の書き方
この問題を解決するのがジェネリクスです。関数名の後ろに<T>という型変数(型引数)を追加します。
function identity(value: T): T {
return value;
}
const a = identity("kino"); // string型として扱われる
const b = identity(123); // number型として扱われるTという文字は「型のための引数」だと考えると理解しやすいです。関数の引数に値を渡すのと同じように、<T>には「型」を渡している、というイメージです。慣習としてTが使われますが、複数の型変数がある場合はT、Uのようにアルファベット順で増やしていくのが一般的です。
型推論とは?<T>を省略できる場面
ジェネリクスは、呼び出す側で毎回型を指定しなくても、TypeScriptが自動で型を推論してくれる場合があります。
const c = identity("kino"); // を省略しても、渡した値からstring型と推論される型推論についての詳しい仕組みは、別記事で解説しているのでこちらもあわせてどうぞ。
any型との違い
ジェネリクスを学び始めると、「any型を使えば同じことができるのでは?」という疑問が必ず出てきます。実際に比較してみると、違いがはっきりします。
function identityAny(value: any): any {
return value;
}
const x = identityAny("kino");
x.toFixed(); // stringにtoFixedは無いのに、コンパイルエラーにならない| 項目 | any | ジェネリクス(<T>) |
|---|---|---|
| 型情報 | 消える(何でも許可) | 保持される |
| 入力補完 | 効きにくい | 型に応じて効く |
| 安全性 | 低い(typoに気づけない) | 高い |
anyとunknownの違いについては、こちらの記事でさらに詳しく解説しています。
ジェネリクスのメリット
- 型ごとに同じ関数を何度も書かずに済む(コードの重複を減らせる)
- anyと違い、型情報を保ったまま処理できる
- 呼び出す型に応じてエディタの入力補完が効く
ジェネリクスのデメリット・注意点
便利な一方で、使いすぎには注意が必要だと感じています。
- 型変数が増えるとコードが読みにくくなりやすい
- 無条件に
Tを受け取ると、意図しない型まで通ってしまうことがある(extendsで制約を付けると防げます) - 初心者のうちは「とりあえずジェネリクス」にせず、必要になった箇所から使う方が理解しやすい
実務で使う場面:React・Promiseでの例
ジェネリクスというと構えてしまいますが、実はTypeScriptを書いていると意識せずに使っていることが多いです。
// Promise<T>:API通信の戻り値の型を指定する
async function fetchUser(id: string): Promise<{ name: string; age: number }> {
const res = await fetch(`/api/users/${id}`);
return res.json();
}
// React:useStateでも<T>がよく使われる
const [user, setUser] = useState<{ name: string; age: number } | null>(null);Promise<T>やuseState<T>の<>の部分も、実はジェネリクスの仕組みです。「PromiseやuseStateという入れ物に、どの型を入れるか」を指定していると考えると、身近な存在に感じられました。実際にReactでAPI連携の実装をする中で、ジェネリクスの意味を意識する場面が何度もありました。
よくあるエラー
function getId(param: T): number {
return param.id;
// Property 'id' does not exist on type 'T'.
}これは、Tが「どんな型か分からない」状態のまま.idを使おうとして起きるエラーです。extendsを使って、Tが持つべき形をあらかじめ制約しておくと解決します。
function getId(param: T): number {
return param.id; // OK
}よくある質問
Q. ジェネリクスとは何ですか?
A. 型を後から指定できる仕組みで、同じ処理を複数の型で使い回すために使います。
Q. <T>のTって何ですか?
A. 「型のための引数(型変数)」です。慣習的にTという名前が使われますが、自由に名付けられます。
Q. any型との違いは何ですか?
A. anyは型情報が消えてしまいますが、ジェネリクスは型情報を保ったまま処理できるため、入力補完や型チェックが効きます。
Q. ジェネリクスはいつ使えばいいですか?
A. 「同じ処理を複数の型に対して行いたいとき」が目安です。配列操作、API通信のレスポンス型、Reactのstateなどでよく使われます。
まとめ
- ジェネリクスは「型を後から指定できる仕組み」で、同じ処理を型ごとに書き直す無駄を防げる
<T>は型のための引数、というイメージで理解すると腹落ちしやすい- anyと違い型情報を保持できるため、実務ではAPI通信やReactのstateなどで頻繁に使われる
公式ドキュメントにも、今回紹介した内容を含むより詳しい解説があります。
もう少し実践的な使い方まで知りたい場合は、こちらの解説記事や動画も参考になります。
▶ 【TypeScript】ジェネリクスも便利だよ #初心者向け(Qiita)
▶ Learn TypeScript With This Crash Course(freeCodeCamp)







