この投稿は「ジェネリクス - TypeScript技術書 by YYTypeScript」をくだけた言葉でリメイクしたものです。
ここに2つの文字列のどちらかを五分五分の確率で返す関数があるよ。
function chooseRandomlyString(v1: string, v2: string): string {
return Math.random() <= 0.5 ? v1 : v2;
}
対戦結果とかおみくじとか、いろいろ使えて便利!
const winOrLose = chooseRandomlyString("勝ち", "負け");
数字にも対応したぞ↓
function chooseRandomlyNumber(v1: number, v2: number): number {
return Math.random() <= 0.5 ? v1 : v2;
}
const num: number = chooseRandomlyNumber(1, 2);
URL版も作った! 広告のA/Bテストとかにも使えて便利だね。
function chooseRandomlyURL(v1: URL, v2: URL): URL {
return Math.random() <= 0.5 ? v1 : v2;
}
const url: URL = chooseRandomlyURL(urlA, urlB);
ん……、気がついたら同じような関数、3つになったぞ……
function chooseRandomlyString(v1: string, v2: string): string {
return Math.random() <= 0.5 ? v1 : v2;
}
function chooseRandomlyNumber(v1: number, v2: number): number {
return Math.random() <= 0.5 ? v1 : v2;
}
function chooseRandomlyURL(v1: URL, v2: URL): URL {
return Math.random() <= 0.5 ? v1 : v2;
}
リファクタリングだ!共通化だ!
function chooseRandomly(v1: any, v2: any): any {
return Math.random() <= 0.5 ? v1 : v2;
}
any
にしたからどんな型も扱える。天才。
let str = chooseRandomly(0, 1);
str = str.toLowerCase();
あれ、なんか実行時にエラー出るんだけど……😱
TypeError: str.toLowerCase is not a function
string
入れるところにnumber
入れてたー😱
さっきまでは、ちゃんとstring
型とかnumber
型を書いて、コンパイラさんがチェックできるようにしてたからなあ。今までこんなバグらせ方、あり得なかったのになあ……。
もうany
型だし、コンパイラさんもここはわからないよな……。しょうがないよな。。
・・・
コンパイラがチェックできるようにしようとすると、関数を量産しないといけない。。
かといって、関数を共通化しようとすると、コンパイラのチェックが効かなくなってしまう。。
悩ましい。
・・・
まてよ、
こんなふうに型も引数みたいに扱えたらいいのに!
そしたら、コンパイラさんも変なバグに気づいて教えてくれるのに!
function chooseRandomly<type>(v1: <type>, v2: <type>): <type> {
return Math.random() <= 0.5 ? v1 : v2;
}
chooseRandomly<string>("勝ち", "負け");
chooseRandomly<number>(1, 2);
chooseRandomly<URL>(urlA, urlB);
TypeScriptにこんな機能あったらな──!
・・・
それがジェネリクスです。
ジェネリクスを使うと、型の安全性とコードの共通化を両立できます!
function chooseRandomly<T>(v1: T, v2: T): T {
return Math.random() <= 0.5 ? v1 : v2;
}
さきほどのバグったコードも、コンパイルチェックで見つけられるようになります。
let str = chooseRandomly<string>(0, 1); // コンパイルエラー
str = str.toLowerCase();
コンパイラさん「Argument of type '0' is not assignable to parameter of type 'string'.」
めでたし、めでたし。