カテゴリ: TypeScript 更新日: 2025/12/09

TypeScriptでジェネリック関数を定義する基本構文を徹底解説!初心者でも理解できるGenerics入門

TypeScriptでジェネリック関数を定義する基本構文
TypeScriptでジェネリック関数を定義する基本構文

先生と生徒の会話形式で理解しよう

生徒

「先生、TypeScriptの“ジェネリック関数”っていう言葉を聞いたんですが、いったい何なんですか?」

先生

「良い質問ですね。TypeScriptの“ジェネリクス(Generics)”は、いろいろな型に対応できる関数を作る仕組みなんです。」

生徒

「いろいろな型に対応できるってどういう意味ですか?」

先生

「たとえば、文字でも数値でも同じように処理したいとき、ジェネリクスを使うと、1つの関数でどちらにも対応できるようになるんです。」

生徒

「なるほど!でも、TypeScriptでどう書くんですか?」

先生

「では、ジェネリック関数の基本構文を具体的に見ていきましょう!」

1. ジェネリック関数とは?

1. ジェネリック関数とは?
1. ジェネリック関数とは?

TypeScriptのジェネリック関数(Generic Function)とは、異なる型でも共通の処理を行えるようにする関数のことです。通常の関数では、引数や戻り値の型を固定してしまいますが、ジェネリクスを使うと、呼び出し時に型を自由に指定できます。

たとえば、「文字列を受け取る関数」と「数値を受け取る関数」をそれぞれ書く代わりに、ジェネリック関数を使えば1つの関数で両方に対応できるのです。これにより、コードの再利用性(同じ処理を何度も書かなくてよい)が高まります。

2. ジェネリック関数の基本構文

2. ジェネリック関数の基本構文
2. ジェネリック関数の基本構文

ジェネリック関数は、関数名の前に山かっこ「<>」を使って型パラメータを指定します。この中に一時的な型の名前を入れます。慣例的に、T(Typeの略)がよく使われます。

基本的な構文は次のようになります。


function 関数名<T>(引数: T): T {
    return 引数;
}

この構文の意味をひとつずつ見ていきましょう。

  • <T>:型パラメータです。ここでTという型を仮で定義します。
  • (引数: T):引数の型をTにしています。つまり、呼び出すときに実際の型が入ります。
  • : T:戻り値の型もTなので、受け取った型と同じ型を返すという意味です。

3. ジェネリック関数の実例を見てみよう

3. ジェネリック関数の実例を見てみよう
3. ジェネリック関数の実例を見てみよう

たとえば、渡された値をそのまま返す関数を作ってみます。ジェネリック関数を使うと、型を固定せずに定義できます。


function echoValue<T>(value: T): T {
    return value;
}

// 文字列の場合
console.log(echoValue("Hello TypeScript!"));

// 数値の場合
console.log(echoValue(123));

このコードを実行すると、次のような結果になります。


Hello TypeScript!
123

このように、echoValue関数は、渡した値が文字列でも数値でも正しく動作します。これは、型パラメータTが呼び出し時に自動的に推論(判断)されるためです。

4. 型を明示的に指定する書き方

4. 型を明示的に指定する書き方
4. 型を明示的に指定する書き方

TypeScriptのジェネリクスでは、型推論に任せることもできますが、明示的に型を指定することもできます。型を指定するには、関数を呼び出すときに山かっこ「<>」を使って型名を渡します。


console.log(echoValue<string>("TypeScript勉強中"));
console.log(echoValue<number>(2025));

このように書くことで、「この関数は文字列を扱う」「この関数は数値を扱う」と明確に示すことができます。

5. 複数の型パラメータを使う

5. 複数の型パラメータを使う
5. 複数の型パラメータを使う

ジェネリック関数は、1つの型だけでなく、複数の型を扱うこともできます。たとえば、2つの異なる型を引数にとる関数を作る場合、次のように書きます。


function showPair<T, U>(first: T, second: U): void {
    console.log(`1つ目: ${first}, 2つ目: ${second}`);
}

showPair("りんご", 100);
showPair(true, "TypeScript");

このコードでは、TUという2つの型パラメータを定義しています。これにより、異なる型を同時に扱えるようになります。

6. ジェネリック関数を使うメリット

6. ジェネリック関数を使うメリット
6. ジェネリック関数を使うメリット

ジェネリック関数を使う最大のメリットは、型の安全性と柔軟性を両立できることです。具体的には次のような利点があります。

  • 型安全(type safety): 間違った型を渡したときにコンパイルエラーで気づけます。
  • 再利用性(reusability): 同じ処理を複数の型で共通化できます。
  • 明確な型推論: TypeScriptが自動で型を判断してくれるので、コードがシンプルになります。

たとえば、配列をそのまま返す関数を作る場合も、ジェネリクスを使うと簡単に書けます。


function identityArray<T>(arr: T[]): T[] {
    return arr;
}

console.log(identityArray([1, 2, 3]));
console.log(identityArray(["A", "B", "C"]));

このように、1つの関数でさまざまな型の配列を処理できるのがジェネリクスの強みです。

7. any型との違いを理解しよう

7. any型との違いを理解しよう
7. any型との違いを理解しよう

「いろいろな型を扱えるなら、any型を使えばいいのでは?」と思うかもしれません。しかし、any型は型チェックを行わないため、プログラムの安全性が下がります。

一方、ジェネリクスは「型を柔軟に扱いながらも、その型を保持」します。つまり、渡した型情報が関数内でも維持されるのです。これが大きな違いです。


// any型の例(型情報が失われる)
function anyEcho(value: any): any {
    return value;
}

// Genericsの例(型情報を保持)
function genericEcho<T>(value: T): T {
    return value;
}

let str = genericEcho("TypeScript");
// strはstring型として扱われる(型推論が有効)

このように、ジェネリクスを使うと、型の安全性を保ちながら柔軟なコードを書くことができます。

まとめ

まとめ
まとめ

TypeScriptのジェネリック関数は、さまざまな型を柔軟に扱いながら、ひとつの共通した処理を安全に保つための重要な仕組みです。この記事で取り上げた基本構文や型パラメータの考え方は、ジェネリクスを理解するうえで欠かせない基礎となります。特に、ジェネリクスの特徴である「呼び出し時に型を決められる仕組み」は、コードの再利用性を飛躍的に高め、同じ処理を複数回書く必要をなくすため、効率的なプログラム設計につながります。また、ジェネリック関数では型推論が非常に優秀で、複雑なコードでも正しい型を保ちながら扱うことができる点も利点として挙げられます。 さらに、複数の型パラメータを使った関数設計は、柔軟かつ表現力豊かなコード構築に役立ちます。異なる型を同時に扱う構造は多数のプログラムで必要とされ、そのたびにジェネリクスのメリットを活かすことで、安全性や保守性の面で大きく貢献してくれます。特に、配列や複数データの取り扱いでジェネリクスを使うと、型情報を保ったまま汎用的な処理を書くことができます。型の矛盾を避けながら、より読みやすく整ったコードを維持できる点は、学習者にとって理解を深める良いきっかけとなるでしょう。 また、any型との違いを実際のコード比較で見てきたように、型の安全性を意識した設計ではジェネリクスが大きな効果を発揮します。特定の型に依存しない柔軟さを残しながら、正しい型推論を維持できることはプログラムの堅牢性を支える重要な視点です。型情報が失われるany型と対照的に、ジェネリクスでは渡された型のまま扱えるため、関数内でも意図しない動作を防ぎやすくなります。 以下に、今回の記事内容を振り返るためのサンプルコードを追加します。ジェネリクスを活用した簡単な関数とクラスを組み合わせた例です。

サンプルコードで理解を深めよう


class Wrapper<T> {
    private item: T;
    constructor(item: T) {
        this.item = item;
    }
    getItem(): T {
        return this.item;
    }
}

function wrapAndShow<T>(value: T): void {
    const wrapped = new Wrapper<T>(value);
    console.log("ラップされた値:", wrapped.getItem());
}

wrapAndShow("文字列の例");
wrapAndShow(456);
wrapAndShow(true);

この例では、ジェネリッククラスとジェネリック関数を同時に活用し、どのような型でも扱える柔軟な構造を構築しています。このようにジェネリクスは関数だけでなく、クラス、配列、データ構造にも応用でき、扱う型に統一性を持たせながら多様なロジックに対応できる強力な道具となります。扱うデータが増えるほどジェネリクスの価値は高まり、プログラム全体の見通しが良くなるため、継続して学びながらさまざまな場面で利用していくことで理解がより深まるでしょう。

先生と生徒の振り返り会話

生徒

「先生、ジェネリック関数って最初はむずかしいものだと思っていたけれど、型をそのまま維持しながら使えるところがとても便利だと感じました!」

先生

「その理解はとても良いですね。型が変わっても同じ関数で処理できるのは、ジェネリクスの大きな魅力です。特に配列や複数データを扱う場面では役立ちますよ。」

生徒

「any型と違って型が失われないという点も安心できますね。間違えて別の型を扱ってしまう心配が減りそうです!」

先生

「その通りです。ジェネリクスは柔軟さと安全性の両方を持っているので、さまざまなアプリケーションで活躍します。これからもいろいろなパターンを試して、理解を深めていきましょう。」

生徒

「はい!今回のコードも参考にしながら、もっと多くのケースでジェネリクスを使ってみます!」

カテゴリの一覧へ
新着記事
New1
TypeScript
TypeScriptでパスエイリアスを設定する方法!baseUrlとpathsでコードをスッキリ整理
New2
JavaScript
JavaScriptのfor文の書き方を初心者向けにやさしく解説
New3
JavaScript
JavaScriptの関数でよくあるエラーとその解決法まとめ
New4
JavaScript
JavaScriptのイベント処理でよくあるエラーとその対処法
人気記事
No.1
Java&Spring記事人気No1
JavaScript
JavaScriptのインストール方法まとめ!Windows・Mac・Linux別にステップ解説
No.2
Java&Spring記事人気No2
JavaScript
JavaScriptのマウスイベントの使い方(click, mouseoverなど)
No.3
Java&Spring記事人気No3
JavaScript
JavaScriptのtoStringとString関数の違いを初心者向けに解説
No.4
Java&Spring記事人気No4
JavaScript
JavaScriptの純粋関数(pure function)と副作用の違いを理解しよう
No.5
Java&Spring記事人気No5
JavaScript
JavaScriptプログラムの実行方法まとめ!ブラウザ・Node.js・コンソールの使い方
No.6
Java&Spring記事人気No6
JavaScript
JavaScriptで文字列をforループで1文字ずつ処理する方法!初心者向け解説
No.7
Java&Spring記事人気No7
TypeScript
TypeScript学習におすすめの無料教材・リファレンスサイト【初心者向け】
No.8
Java&Spring記事人気No8
TypeScript
TypeScriptの始め方:開発環境の構築手順【初心者向け】