mizkog-logo

Web制作の備忘録

HomeZenn

Genericsの基礎

Genericsとは?

型の決定を遅延できるもの。
基本的には以下のように記述する。

type Foo<T> = {
 value: T;
};

const foo: Foo<number> = {
 value: 0,
};


Genericsで使用されるTやKなどの由来

Genericsで使用されるTやKなどの由来は以下の通り。

  • T:Type
  • K:Key
  • U:Unknown
  • E:Element

以上の4つが慣例的によく使われるので覚えておくと良い。

Genericsの良さ

後から使いまわしたりする際に、型を自由に定義することができる。

type Foo<T> = {
 value: T;
};

const foo1: Foo<number> = {
 value: 0,
};
const foo2: Foo<string> = {
 value: "",
};
const foo3: Foo<number[]> = {
 value: [1, 2, 3],
};

Genericsじゃなかったらvalueを定義し直さなければならなくなる。

Genericsのユースケース

以下の例のように後からJapaneseやAmericanの型が決定させたい場合に使われる。

type User<T> = {
 name: string;
 state: T;
};

type Japanese = User<"東京都" | "大阪府">
type American = User<"CA" | "NY">

const user1: Japanese = {
 name: "田中",
 state: "東京都",
};

const user2: American = {
 name: "taylor",
 state:"CA",
};


Genericsの初期値

<T = string>とすることで、初期値がstringとなる。
そのため、foo1でFoo<string>としなくても、初期値はstringだと暗黙的に分かっているので問題ない。

type Foo<T = string> = {
 value: T;
};

const foo1: Foo = {
 value: "",
};
const foo2: Foo<number> = {
 value: 111,
}


Genericsのextendsによる型制約

Genericsの型引数に制約を加えたい時にextendsによる型制約を用いる。
以下のコードだと、extendsでstringを指定しているので、stringに互換性がないnumberはエラーとなる。

type Foo<T extends string> = {
 value: T;
};

const foo1: Foo<string> = {
 value: "",
};
const foo2: Foo<"abc"> = {
 value: "abc",
};
const foo3: Foo<number> = { // 型 'number' は制約 'string' を満たしていません。
 value: 123,
};


Genericsの初期値とextendsによる型制約の組み合わせ

シンプルに = string と繋げて記述すればOK。

type Foo<T extends string = string> = {
 value: T;
};

const foo1: Foo = {
 value: "",
};
const foo2: Foo<"abc"> = {
 value: "abc",
};