デフォルト型引数
関数の引数にデフォルト値を指定するように、ジェネリクスでもデフォルトの型引数を指定することができます。
例としてエラーイベントを表すMyErrorEventという型を定義してみます。この型は発生した任意のエラーオブジェクトとその種類を文字列で保持する型です。
tstypeMyErrorEvent <T > = {error :T ;type : string;};
tstypeMyErrorEvent <T > = {error :T ;type : string;};
この型は次のように利用できます。
tsclassNetworkError extendsError {constructor(e ?: string) {super(e );this.name = new.target .name ;}}consterrorEvent :MyErrorEvent <Error > = {error : newError ("エラーです"),type : "syntax",};constnetworkErrorEvent :MyErrorEvent <NetworkError > = {error : newNetworkError ("ネットワークエラーです"),type : "network",};
tsclassNetworkError extendsError {constructor(e ?: string) {super(e );this.name = new.target .name ;}}consterrorEvent :MyErrorEvent <Error > = {error : newError ("エラーです"),type : "syntax",};constnetworkErrorEvent :MyErrorEvent <NetworkError > = {error : newNetworkError ("ネットワークエラーです"),type : "network",};
例外処理を記述する時にNetworkErrorのように対応するエラークラスをすべて用意することはなく、標準のErrorで対応してしまうケースも多くありますが、今の状態ではMyErrorEventのジェネリクスの型Tを常に指定する必要があり非常に面倒です。
ts// 型 T が必須なので、MyErrorEvent<Error>と指定する必要がある。constGeneric type 'MyErrorEvent' requires 1 type argument(s).2314Generic type 'MyErrorEvent' requires 1 type argument(s).errorEvent := { MyErrorEvent error : newError ("エラーです"),type : "syntax",};
ts// 型 T が必須なので、MyErrorEvent<Error>と指定する必要がある。constGeneric type 'MyErrorEvent' requires 1 type argument(s).2314Generic type 'MyErrorEvent' requires 1 type argument(s).errorEvent := { MyErrorEvent error : newError ("エラーです"),type : "syntax",};
そこで、<T = Error>とすることでデフォルト型引数としてErrorを指定します。
tstypeMyErrorEvent <T =Error > = {error :T ;type : string;};
tstypeMyErrorEvent <T =Error > = {error :T ;type : string;};
デフォルト型引数としてErrorを指定することでジェネリクスの型Tは必要な時だけ指定して、何も指定してない場合は自動でErrorとすることができます。
ts// デフォルト型引数を指定した事で Error の型指定を省略できるconsterrorEvent :MyErrorEvent = {error : newError ("エラーです"),type : "syntax",};constnetworkErrorEvent :MyErrorEvent <NetworkError > = {error : newNetworkError ("ネットワークエラーです"),type : "network",};
ts// デフォルト型引数を指定した事で Error の型指定を省略できるconsterrorEvent :MyErrorEvent = {error : newError ("エラーです"),type : "syntax",};constnetworkErrorEvent :MyErrorEvent <NetworkError > = {error : newNetworkError ("ネットワークエラーです"),type : "network",};
型引数の制約と併用する
ある型の部分型であることを指定しながら、かつ省略時はデフォルト型を指定する合わせ技もできます。型引数の制約については専門のページがありますのでそちらを参照してください。
📄️ 型引数の制約
TypeScriptではジェネリクスの型引数を特定の型に限定することができます。
MyErrorEventに与えられる型TをErrorのサブクラスに限定しつつ、省略時はSyntaxErrorとしたい場合は次のような書き方になります。
tstypeMyErrorEvent <T extendsError =SyntaxError > = {error :T ;type : string;};
tstypeMyErrorEvent <T extendsError =SyntaxError > = {error :T ;type : string;};
型引数の制約とデフォルト型引数の両立をする場合はデフォルト型引数が制約を満たしている必要があります。
tsinterfaceType 'bigint' does not satisfy the constraint 'string | number'.2344Type 'bigint' does not satisfy the constraint 'string | number'.Serializable <T extends string | number =bigint > {value :T ;toString (): string;}
tsinterfaceType 'bigint' does not satisfy the constraint 'string | number'.2344Type 'bigint' does not satisfy the constraint 'string | number'.Serializable <T extends string | number =bigint > {value :T ;toString (): string;}
この例はstring | number型に制約しているにもかかわらず、デフォルト型引数にbigint型を指定しています。そのため制約を満足することができずTypeScriptから指摘を受けます。
デフォルト型引数をジェネリクスで指定する
ジェネリクスが複数あるとき、デフォルト型引数をデフォルト型引数で指定できます。
tsclassAubergine <A ,B =A ,C =B > {private readonlya :A ;private readonlyb :B ;private readonlyc :C ;public constructor(a :A ,b :B ,c :C ) {this.a =a ;this.b =b ;this.c =c ;}// ...}
tsclassAubergine <A ,B =A ,C =B > {private readonlya :A ;private readonlyb :B ;private readonlyc :C ;public constructor(a :A ,b :B ,c :C ) {this.a =a ;this.b =b ;this.c =c ;}// ...}
デフォルト型引数は左から順に参照されるため、左にあるジェネリクスが右のジェネリクスを指定することはできません。
tsclassType parameter defaults can only reference previously declared type parameters.Aubergine <A =, B , B C =B > {
Required type parameters may not follow optional type parameters.2744
2706Type parameter defaults can only reference previously declared type parameters.
Required type parameters may not follow optional type parameters.private readonlya :A ;private readonlyb :B ;private readonlyc :C ;public constructor(a :A ,b :B ,c :C ) {this.a =a ;this.b =b ;this.c =c ;}}
tsclassType parameter defaults can only reference previously declared type parameters.Aubergine <A =, B , B C =B > {
Required type parameters may not follow optional type parameters.2744
2706Type parameter defaults can only reference previously declared type parameters.
Required type parameters may not follow optional type parameters.private readonlya :A ;private readonlyb :B ;private readonlyc :C ;public constructor(a :A ,b :B ,c :C ) {this.a =a ;this.b =b ;this.c =c ;}}