type SomeType<T extends object = any> = {
value: T;
};
使おうと思って調べていたライブラリのd.ts
ファイルを見ていたらこんな感じの型があった。読み方がわからなかったので調べた。
extends
まずは<T extends object>
。ジェネリックでextends
を使うことによって、T
がとれる型の範囲を決めます。下記の例では、T
がobject
でextends
されているので、T
はobject
型、またはobject
のサブクラス型を取ることができます。
type SomeType<T extends object> = {
value: T;
};
const hoge1: SomeType<object> = {
value: { value: "object" },
};
// => ok
const hoge2: SomeType<string[]> = {
value: [],
};
// => ok
const hoge3: SomeType<string> = {
value: "record",
};
// => Type 'string' does not satisfy the constraint 'object'.
array
はobject
のサブクラスなので利用できますが、string
はサブクラスでないので使えません。
ちなみに型のヒエラルキーはこのようになっています。
3. All About Types - Programming TypeScript Book
デフォルト型
次にジェネリックのデフォルト型について見てみます。
type SomeType<T = object> = {
value: T;
};
const hoge1: SomeType = {
value: { value: "object" },
};
// => ok
const hoge2: SomeType<object> = {
value: { value: "object" },
};
// => ok
const hoge3: SomeType<string> = {
value: "string",
};
// => ok
ジェネリックのデフォルト型を設定しておくと、hoge1
のように型利用時にジェネリック型を明示的に指定しなくても推論してくれます。デフォルト型はobject
になっていますが、extends
で制約されているわけではないので、string
型も指定できます。
extends とデフォルト型
最後に冒頭に書いた型について。extends
で型を制約しつつ、デフォルト型を設定する場合、変数設定時等でジェネリック型を明示的に指定した際に制約が課され、指定しない場合はデフォルト型が適応されます。
type SomeType<T extends object = any> = {
value: T;
};
const hoge1: SomeType = {
value: "string",
};
// => ok
const hoge2: SomeType<string> = {
value: "string",
};
// => Type 'string' does not satisfy the constraint 'object'.
const hoge3: SomeType<string[]> = {
value: [],
};
// => ok
hoge1
はジェネリック型を明示的にしていないため、T
がany
型になりますが、hoge2
は明示的にstring
を指定しているため、extends object
の制約でエラーになります。