JavaScript
TypeScript

TypeScriptのジェネリックについて調べてみた

ジェネリックとは

TypeScriptのジェネリックとは、型を抽象化してコードを短くする時に便利な機能である。これだけでは分かりにくいので例を出しながら見ていく。

なぜジェネリックを使うのか

5つの例をもとに、順番にどういった時にジェネリックを使えば良いのか見ていく。

①同じような機能を持つ2つの関数のコード

function hello1() {
    alert('taro');
}

function hello2() {
    alert('hanako');
}

hello1();
hello2();

→似たような機能を一個ずつ書くのは冗長なので、まとめたほうが良い

②string型の引数wordを使用して、関数を一つにまとめる

function hello1(word: string) {
    alert(word);
}

hello1('taro');  //string型
hello1('hanako');  //string型

→関数を一つにまとめられた。でも型が同じだからまとめられたが、型が違う時はまとめられるのだろうか?

③string型の引数を持つ関数と、number型の引数を持つ関数

function hello1(word: string) {
    alert(word);
}

function hello2(word: number) {
    alert(word);
}

hello1('taro');  //string型
hello2(5);  //number型

→先ほど、関数を一つにまとめられたのは引数を使ったからであり、引数のデータ型が同じだったからできたわけである。でも今回はstring型とnumber型で違うので一つにまとめられない

④型が違うなら、any型を使えば解決できそう

function hello1(word: any) {
    alert(word);
}

hello1('taro');
hello1(5);

→確かにこれでも問題ないが、anyは型チェックを行わないので、なるべく使いたくない。

⑤型引数を使えば、ジェネリックで問題を解決できる

function hello1<T>(word: T) {
    alert(word);
}

hello1<string>('taro');
hello1<number>(5);


//型引数が2つ以上の時はカンマで区切ることでまとめられる
function hello1<T, U>(word: T, num:U) {
    alert(word);
    alert(num);
}

hello1<string, number>('taro', 5);

→ジェネリック型を利用する際は、<>を使用し、Tを記述することで型引数を抽象化する。Tを使うのは慣習によるものらしいが、任意の値でも問題ない。関数呼び出し時に型宣言をしているが、型引数の抽象化されたTによってどのデータ型でも対応できるようになり、それに伴い引数の値も変化する。

型引数の名前には「T」を使用することが多いが、2つ以上の場合はアルファベット順に「T」「U」「V」や、「T1」「T2」「T3」などが慣習的に使用される。

参考記事

http://www.buildinsider.net/language/tsgeneric/01
http://jsstudy.hatenablog.com/entry/typescript-generic-type