デフォルト型引数
関数の引数にデフォルト値を指定するように、ジェネリクスでもデフォルトの型引数を指定することができます。
例としてエラーイベントを表すMyErrorEvent
という型を定義してみます。この型は発生した任意のエラーオブジェクトとその種類を文字列で保持する型です。
ts
typeMyErrorEvent <T > = {error :T ;type : string;};
ts
typeMyErrorEvent <T > = {error :T ;type : string;};
この型は次のように利用できます。
ts
classNetworkError 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",};
ts
classNetworkError 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
を指定します。
ts
typeMyErrorEvent <T =Error > = {error :T ;type : string;};
ts
typeMyErrorEvent <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",};
型引数の制約と併用する
ある型の部分型であることを指定しながら、かつ省略時はデフォルト型を指定する合わせ技もできます。型引数の制約については専門のページがありますのでそちらを参照してください。
📄️ 型引数の制約
MyErrorEvent
に与えられる型T
をError
のサブクラスに限定しつつ、省略時はSyntaxError
としたい場合は次のような書き方になります。
ts
typeMyErrorEvent <T extendsError =SyntaxError > = {error :T ;type : string;};
ts
typeMyErrorEvent <T extendsError =SyntaxError > = {error :T ;type : string;};
型引数の制約とデフォルト型引数の両立をする場合はデフォルト型引数が制約を満たしている必要があります。
ts
interfaceType '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;}
ts
interfaceType '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から指摘を受けます。
デフォルト型引数をジェネリクスで指定する
ジェネリクスが複数あるとき、デフォルト型引数をデフォルト型引数で指定できます。
ts
classAubergine <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 ;}// ...}
ts
classAubergine <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 ;}// ...}
デフォルト型引数は左から順に参照されるため、左にあるジェネリクスが右のジェネリクスを指定することはできません。
ts
classType 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 ;}}
ts
classType 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 ;}}