1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【学習】TypeScriptの `Generic` / `Utility Types` の基本概念を学ぶ

1
Last updated at Posted at 2026-09-06

はじめに

GenericUtility Types について、それぞれ聞いたことはあるけど詳しい内容や関係性についてはよく知らなかったので、学習がてらまとめてみた。

1. Genericとは

型を後から渡せる仕組み。

  • Genericが便利なのは、「型の関係」を表せるから
  • 入力の型 → T → 出力の型
  • 構造は同じだけど、中身の型だけ違うものを扱える
type ApiResponse<T> = {
  data: T;
  error: string | null;
};

と一度作っておけば、

ApiResponse<User>
ApiResponse<Product>
ApiResponse<Order>
ApiResponse<Comment>

と使い回せる。

2. Utility Typesとは

既存の型を加工して新しい型を作る仕組み。
TypeScriptに最初からたくさん用意されている。

ここでは、以下の基本的なUtility Typesについて学んでいく。

Partial
Required
Readonly
Pick
Omit
Record
ReturnType

2.1 Partial

type User = {
  id: number;
  name: string;
  age: number;
};

これをPartialを用いて

type UpdateUser = Partial<User>;

とすると、

type UpdateUser = {
  id?: number;
  name?: string;
  age?: number;
};

になる。

つまりPartialとは、全てoptionalにするUtility Typeである。

用途

例えば、ユーザー情報の更新を行うとき、

function updateUser(
  id: number,
  data: Partial<User>
) {
}

とすれば、

updateUser(1, {
  name: "Taro"
});

のように、一部だけ更新することができる。

2.2 Required

Partial とは逆に、

type RequiredUser = Required<User>;

とすると、

{
  id: number;
  name: string;
  age: number;
}

のように全て必須となる。

2.3 Readonly

type ReadonlyUser = Readonly<User>;

とすると、

const user: ReadonlyUser = {
  id: 1,
  name: "Hachiware",
  age: 30
};

に対して、

user.name = "Usagi";

ができなくなる。

つまり、Readonlyは読み取り専用にするUtility Typeである。

2.4 Pick

type User = {
  id: number;
  name: string;
  age: number;
  email: string;
};

これを、

type UserPreview = Pick<User, "id" | "name">;

とすると、

type UserPreview = {
  id: number;
  name: string;
};

になる。

つまり、Pickは必要なプロパティだけ取り出すUtility Typeである。

2.5 Omit

OmitPickの逆のようなもので、

type User = {
  id: number;
  name: string;
  age: number;
  email: string;
};

に対して、

type UserWithoutEmail = Omit<User, "email">;

とすると、

{
  id: number;
  name: string;
  age: number;
}

になる。

つまり、指定したプロパティを除外するUtility Typeである。

2.6 Record

type UserRole = Record<string, string>;

これは、

{
  [key: string]: string;
}

のような型になる。
例えば、以下のような形。

const roles: Record<string, string> = {
  admin: "管理者",
  user: "一般ユーザー",
  guest: "ゲスト"
};

つまり、Recordはキーと値の型を指定して、オブジェクト型を作るUtility Typesである。

他にも、以下のような使い方がある。

type Status = "loading" | "success" | "error";

const labels: Record<Status, string> = {
  loading: "読み込み中",
  success: "成功",
  error: "エラー"
};

この場合、Statusに新しい値を追加したのにlabelsを追加し忘れると、TypeScriptがエラーを出して教えてくれる。

2.7 ReturnType

function getUser() {
  return {
    id: 1,
    name: "Taro"
  };
}

これに、

type User = ReturnType<typeof getUser>;

とすると、

type User = {
  id: number;
  name: string;
};

になる。

つまり、

typeof getUser

getUserという関数そのものの型を渡して、

ReturnType<...>

でその関数の戻り値の型を取り出している。

3. GenericUtility Types のつながり

多くのUtility Typesは、Genericを利用して作られている。

例えば、

Partial<T>

という形。

TUserを渡すと、

Partial<User>

になる。

つまり、

Generic
 ↓
型を受け取る仕組み
 ↓
Utility Types
 ↓
型を受け取って加工する

という関係。

Typescript側の目線から見ると、

Partialを用意
  ↓
「Tにどんな型が入るかは、使うときまで分からない」
  ↓
Generic <T> で受け取る
  ↓
Userが入ってくる
  ↓
Userのプロパティを全部optionalにした型を作る

という仕組み。

補足

ちなみに、Partialは概念的には以下のような仕組みとなっている。

type Partial<T> = {
  [P in keyof T]?: T[P];
};

[P in keyof User]は、Userのキーを1個ずつPにいれて処理するイメージ。)

流れとしては、

Partial<User>
      ↓
T = User
      ↓
keyof T
      ↓
Userのキーを取得
      ↓
各プロパティをoptionalにする
      ↓
Partial<User>

となっている。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?