型変数と型引数【個人学習まとめ】
型変数とは
端的に言えば型を代入する箱。
「変数」といえば、値を代入する箱である。という表現を使われることが多いです。
変数は値を代入できますが、型変数は型を代入することができます。
//変数の使用例
const hensu = "変数です!";
console.log(hensu);
console.log(hensu.length);
//型変数の使用例
function sampleFunction<KataHensu>(value: KataHensu): KataHensu {
console.log(value);
return value;
}
上記の例では、変数と型変数それぞれの使用例です。(変数の方はもう知ってるよ!という方が多いかと思いますが、比較のために用意しました。)
変数hensu
は、一度定義してしまえば値を書き写す必要もなくなりますね。また、コンソールを使って変数に代入されている値を画面に出力したり、length
プロパティを使って代入されている値の長さを取得することもできます。
型変数KataHensu
は、一度定義してしまえば関数sampleFunction
内では一貫して参照可能な型として機能します。
型変数を定義する場合は、変数名を<>
で囲むことによって定義します。上記の例だと<KataHensu>
が型変数KataHensu
を定義している部分になります。
さらに、関数sampleFunction
の引数value
と戻り値にも型変数KataHensu
が利用されていますね。これが一つ上で説明した「関数sampleFunction
内では一貫して参照可能な型として機能します」
に該当します。
つまり、型変数KataHensu
のスコープは関数sampleFunction
の範囲になります。仮に関数sampleFunction
の外で利用しようとしてもエラーとなります。
function sampleFunction<KataHensu>(value: KataHensu): KataHensu {
console.log(value);
return value;
}
+ let errorVarlue: KataHensu;
→ 名前 'KataHensu' が見つかりません。
ここまでで、型変数の名前をKataHensu
としていました。
しかし、TypeScirpt の慣習としてはT
という単一の大文字が使用されます。型変数が 2 つある場合は 2 つ目にU
を、型変数が 3 つある場合は 3 つ目にV
が利用されます。(今回のようにKataHensu
という名前を付けることもできます。逆に利用できないのはclass
やconst
などの予約語です。)
型引数とは
型変数に代入した型のことです。
const sampleValue = sampleFunction<string>("サンプルコードです");
上記のサンプルだとstring
が型引数になります。
型引数を明示的に指定しましたが、変数の"サンプルコードです"
から TypeScript 側が変数の型がstring
であると型推論を行ってくれるので、次のように型引数を省略することも可能です。
const sampleValue2 = sampleFunction("サンプルコードです");
型引数のデフォルト値
「型引数を省略することも可能だ」ということを説明しました。
しかし、型引数が渡されなかった場合やundefined
が渡された場合はどうでしょうか?関数の呼び出し自体は問題なくできますが、関数内部の処理ではエラーが発生してしまう可能性があります。
これを避けるためにも、型引数にデフォルト値を設定することができます。
function createPair<T = number, U = string>(first: T, second: U): [T, U] {
return [first, second];
}
上記の例では、関数createPair
に型変数T
とU
を設定しています。T
のデフォルト値としてnumber
型を、U
にはstring
型を指定しています。デフォルト値を指定する時は=
で結びます。
関数の引数と戻り値は型変数T
とU
をそれぞれ参照しています。
仮に戻り値の順序を入れ替えるとどうでしょうか?
function createPair<T = number, U = string>(first: T, second: U): [T, U] {
- return [first, second];
+ return [second, first ];
→ 型 'U' を型 'T' に割り当てることはできません。
'U' に関連しない可能性のある任意の型で 'T' をインスタンス化できます。
}
型の不一致でエラーとなりました。型引数が十分に機能していることが分かるかと思います。
この関数createPair
を呼び出す時は通常の関数を呼び出すように記述して OK です。
const numAndStr = createPair(123, "あいう");
→ [ 123, 'あいう' ]
const strPair = createPair("苗字", "名前");
→ [ '苗字', '名前' ]
引数のデフォルト値と関数呼び出し時の引数が異なっている場合は、関数呼び出し時にしていている引数の型を優先します。
上記の場合だと、デフォルト値は
T = number
-
U = string
です。
しかし、変数strPair
はどちらもstring
型です。この場合はstring
型が優先されます。
型引数のデフォルト値はあくまでも、型情報が不明確な場合に利用されます。
まとめ
型変数は型を代入する箱。
型引数は、型変数に代入した型。
余談
Reactのサンプルコードを見ていると型引数のT
、U
は頻繁に出てきますね。なんとなーくの理解で進めていた部分があるので今回でしっかり学習できました。
しかしまぁ・・・慣れていないとT
だけ記述されていても分からんなぁ・・・
Discussion