プログラミング

【TypeScript】ジェネリックとは?徹底解説します

タクマ

こんにちは!タクマです。

31歳未経験からエンジニア転職に成功し、

2021年3月より都内の受託開発企業にてWebエンジニアとして働いています。

今回はTypeScriptのジェネリックについて解説します。

「ジェネリックってなに?」という方は、この記事を読めば理解していただける内容となっております。

ぜひ最後まで読んでいただけると嬉しいです。

そもそもジェネリックとは?

ジェネリック(ジェネリクスとも言う)は、使われるまで型が確定していないクラス・関数などを作る際に使用するものになります。

この説明だけではイメージが湧かないと思うので、実際に例をみてみましょう!

ジェネリックを使用しない場合 (関数編)

たとえば、下記のように同じようなコードで別の型を返す関数があるとします。

// number型(引数argumentはnumber型、返り値もnumber型を指定している)
function sample1(argument: number): number {
  return argument;
}

// string型(引数argumentはstring型、返り値もstring型を指定している)
function sample2(argument: string): string {
  return argument;
}

const num = sample1(10);
const str = sample2("HelloWorld!!"); 

console.log(num);   //実行結果:10
console.log(str);   //実行結果:HelloWorld!!

似たような関数なのに、返す型が違うだけで二つの関数を書くのは面倒ですよね。

そんな時に使用するのがジェネリックです。

ジェネリックを使用することで、下記のように書くことができます。

ジェネリックを使用する場合 (関数編)

// 大文字のTを仮の型引数として記述するのが一般的となっている(TはtypeのT)
function sample<T>(argument: T): T {
  return argument;
}

// 関数を呼び出す時に型を指定する
const num = sample<number>(10);
const str = sample<string>("HelloWorld!!"); 

console.log(num);   //実行結果:10
console.log(str);   //実行結果:HelloWorld!!

ジェネリックを使用すると、関数を使い回しできるため、コードが少なくてすみます。

ジェネリックを使用しない場合(クラス編)

次にクラスでジェネリックを使用する例をみてみましょう。

class NumData {
// アクセス制御の装飾子 public をつけて引数を定義すると引数がそのままプロパティとして扱われる
  constructor(public argument: number){
     // this.argument = argument; も必要ない
  }
  getArgument(): number {
    return this.argument;
  }
}


class StrData {
// publicをつけない場合はargumentに値を渡せるよう、下記のように書く
  argument = string;
  constructor(argument: string){
    this.argument = argument;
  }
  getArgument(): string {
    return this.argument;
  }
}



var num = new NumData(10);
var str = new StrData('HelloWorld!!');

console.log(num.getArgument());   //実行結果:10
console.log(str.getArgument());   //実行結果:HelloWorld!!

似たようなコードのクラスなのですが、型が違うためにクラスを二つ定義しています。

しかし、これもジェネリックを使用すればクラスを一つにし、コードを少なくすることができます。

ジェネリックを使用する場合(クラス編)

// 大文字のTを仮の型引数として記述するのが一般的となっている(TはtypeのT)
class Data<T> {
  constructor(public argument: T){
  }
  getArgument(): T {
    return this.argument;
  }
}
  
// インスタンスを作成する時に型を指定する。
  var num = new Data<number>(10);
  var str = new Data<string>('HelloWorld!!');
  
  console.log(num.getArgument());   //実行結果:10
  console.log(str.getArgument());   //実行結果:HelloWorld!!

ジェネリックを使用することによって、クラスが一つですむようになり、コードがかなり少なくなりました。

ジェネリックは複数の型引数を定義することも可能

複数の型引数を定義することもできます。

// 複数の型引数の場合はTやUを使用するのが一般的となっている
function sanmple<T, U, R>(arg1: T, arg2: U, arg3: R) {
  console.log(arg1);   //実行結果:10
  console.log(arg2);   //実行結果:HelloWorld!!
  console.log(arg3);   //実行結果:true
}

sanmple<number, string, Boolean>(10, 'HelloWorld!!', true);

さいごに

いかがでしたでしょう?

TypeScriptのジェネリックについて理解していただけましたでしょうか?

ご質問やご指摘等ある方はコメントしていただければ返信させていただきます。

これからもエンジニアの方、プログラミング初学者の方に役に立つ記事を更新していきますのでよろしくお願いします!

Twitterでも情報発信をしていますので、よかったらフォローをお願いします(^^)

Webエンジニア
タクマ
埼玉県出身の33歳

新卒で入社した専門商社で8年間営業職として勤務

30歳からプログラミングを始め31歳でWebエンジニアに転職成功

受託開発企業での開発を1年弱経験したのち、現在はスタートアップの自社開発企業で開発に従事している
\ Follow me /

COMMENT

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA