2022年3月24日 りあクト! 第4章 TypeScriptで型をご安全に(p.169~)
関数の型宣言にジェネリクスを用いる記法
const toArray = <T>(arg: T, arg2: T): T[] => [arg1, arg2]; toArray(8, 3);
- 第一引数の実引数が型推論されてTがnumber型になります。
- このTは型引数(Type Prameter)でありアルファベットは何を使用しても構いません。
このようにデータ型に束縛されないよう型を抽象化してコードの再利用性を向上させつつ、静的型付け言語の持つ型安全性を維持するプログラミング手法をジェネリックプログラミングと呼びます。 そして、型引数を用いて表現するデータ構造のことをジェネリクスといいます。
const toArrayVariably = <T>(...args: T[]): T[] => [...args]; toArrayVariably(1, 2, 3, 4, 5); //=> [1,2,3,4,5] //=> <number>(...args: number[]): number[] => [...args]; toArrayVariably(6, '7', 8); // =>[eval].ts:3:20 - error TS2345: Argument of type '"7"' is not assignable to parameter of type'number'.
- 変数toArrayVariablyは、同じ型の引数を制限なく受け取り、同じ型の戻り値を配列として返す関数が代入されています。制限なく引数を受け取れるのは、レストパラメーターを使っているからです。
- 変数toArrayVariablyに代入されている関数の引数と戻り値に、ジェネリクスで型付けされています。
<T>
の部分で、型引数Tを宣言しています。宣言後で、型引数T
が使えるようになっています。Tは、抽象的な型を表しています。toArrayVariably(1, 2, 3, 4, 5);
の部分では、第1引数として渡された値が1
であるため、number型として型推論されて型引数の型が決まります。- TypeScriptでは引数の型をあらかじめ指定しないといけませんが、上記のように型引数を使うことで型を固定しないで柔軟に定義出来ます。
TypeScriptでのクラスの扱い
- TypeScriptのクラスはコンストラクタ関数内の変数の型アノテーションを最初に定義する必要があります。
- プロパティ初期化子(= 値)を使えばコンストラクタに引数がないクラスならばコンストラクタを省略してインスタンス化できます。
- プロパティの初期化子を使用する際に型推論を使うこともできます。
- プロパティの初期化子を使う際にreadonlyなどの修飾子を使うこともできます。
- プロパティの初期化子を使う際にアクセス修飾子(public protected private)を使うこともできます。
クラス内でプロパティ初期化子を使用した例を、以下に示します。
class Person { // TypeScriptでは。メンバー変数をクラスの最初で宣言する // ここで宣言しないと、エラーが起こる // = 値は、プロパティ初期化子と呼ばれる // プロパティ初期化子を書いた場合、コンストラクタの記述を省略できる // 初期化子は、クラスがインスタンス化されるときに自動的に実行されます。 readonly name = 'yano'; skill = 'JavaScript'; } const a = new Person(); console.log(a); // => [LOG]: Person: { // "name": "yano", // "skill": "JavaScript" // }
- Personクラス内では、値の書き換え不可である初期値がyanoというnameプロパティとJavaScriptという初期値が入ったskillプロパティを宣言しています。
- nameプロパティは、リテラル型として型推論されます。(readonly修飾子を使っているため)ここでは、型推論を使っていますが、明示的に、
:type
で型を提示することもできます。 - skillプロパティは、String型の
'JavaScript'
が初期値として代入されているのでString型として型推論されます。こちらも:type
で型を提示できます。 - Personクラスのインスタンスを生成すると、引数としてコンストラクタにプロパティの値を渡さなくとも値をそれぞれ持つnameプロパティとskillプロパティを最初から持ったインスタンスが生成できます。