Genericsの基礎

公開日: 2023/05/20 @Miz_dev

TypeScript

Generics とは?

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

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

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

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

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

以上の 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 だと暗黙的に分かっているので問題ない。

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",
};