はじめに
TypeScriptには標準で用意されている Utility Types があり、既存の型を変換して新しい型を作ることができます。
「存在は知ってるけど Partial と Pick くらいしか使ってない」という方も多いのではないでしょうか。実際、実務で使いどころを押さえておくとコードの見通しがかなり良くなります。
この記事では、よく使う Utility Types を 「どんな場面で使うと便利か」 という観点で整理しました。
本記事は @KaraBharat氏のツイート を参考に、実務での使い方を補足してまとめたものです。
ベースとなる型
以降の例ではすべてこの User 型を使います。
interface User {
id: string;
name: string;
email?: string;
role: "admin" | "editor" | "viewer";
}
email がオプショナルになっている点がポイントです。
Partial<T> — 更新リクエストに便利
const updateUser: Partial<User> = { email: "new@domain.com" };
すべてのプロパティをオプショナルにする型です。
使いどころ
- PATCH API のリクエストボディ(変更したいフィールドだけ送る)
- フォームの部分的なバリデーション
-
setStateのようにオブジェクトの一部だけ更新する場面
function updateUser(id: string, data: Partial<User>) {
// data には User のうち好きなフィールドだけ入っていればOK
}
Required<T> — オプショナルを許さない場面に
const completeUser: Required<User> = {
id: "cgjhfgx676",
name: "Adam",
email: "adam@gmail.com", // ← email も必須になる
role: "admin",
};
すべてのプロパティを必須にする型です。Partial の逆ですね。
使いどころ
- DB保存前のバリデーション後の型(「全フィールドが埋まっている」ことを型で保証)
- フォーム送信時の最終チェック
- テストデータの作成(フィールド漏れを防ぐ)
Readonly<T> — うっかり変更を防ぐ
const staticUser: Readonly<User> = {
id: "cgjhfgx676",
name: "Adam",
role: "viewer",
};
// staticUser.role = "admin"; // ← コンパイルエラー!
すべてのプロパティを readonly にする型です。
使いどころ
- API レスポンスをそのまま保持する変数(意図しない書き換え防止)
- Redux の state や、React の props から受け取ったデータ
- 設定値やマスターデータなど、変更されるべきでないオブジェクト
Pick<T, K> — 必要なプロパティだけ抜き出す
type UserSidebar = Pick<User, "name" | "role">;
// { name: string; role: "admin" | "editor" | "viewer" }
使いどころ
- UIコンポーネントに渡す props の型を作るとき
- 一覧画面で表示に必要なフィールドだけ抽出
- GraphQLのフラグメントのような感覚で「この画面ではこれだけ必要」を明示
// サイドバーはユーザーの名前とロールだけ知っていればいい
const SidebarItem: React.FC<UserSidebar> = ({ name, role }) => { ... };
Omit<T, K> — 特定のプロパティを除外する
type NewUserRequest = Omit<User, "id">;
// { name: string; email?: string; role: "admin" | "editor" | "viewer" }
Pick の逆で、指定したキーを除いた型を作ります。
使いどころ
- POST API のリクエスト型(
idはサーバー側で自動生成するので送らない) - フォームの入力型(
createdAtやupdatedAtは入力しない) - 「ほぼ全フィールド使うけど、これだけは不要」というケース
// 新規作成時は id がまだ無いので除外
async function createUser(data: Omit<User, "id">): Promise<User> { ... }
Record<K, T> — キーと値のペアでオブジェクトを定義
const userCache: Record<string, User> = {
uyfhfghgf6: { id: "uyfhfghgf6", name: "James", role: "admin" },
};
使いどころ
- ID をキーにしたルックアップテーブル / キャッシュ
- API レスポンスを
idでインデックスした Map 的構造 - enum や union 型をキーにした設定マッピング
// ロールごとの表示ラベルを定義
const roleLabels: Record<User["role"], string> = {
admin: "管理者",
editor: "編集者",
viewer: "閲覧者",
};
この Record<User["role"], string> パターンは、ロールを追加したときに漏れがあるとコンパイルエラーになるので非常に実用的です。
Exclude<T, U> — Union型から特定の値を除外
type NonAdminRoles = Exclude<User["role"], "admin">;
// "editor" | "viewer"
使いどころ
- 権限チェックで「admin 以外」を型で表現
- 特定のステータスを除いた処理の分岐
- APIのレスポンス型から特定のケースを除外
Extract<T, U> — Union型から特定の値を抽出
type OnlyAdmin = Extract<User["role"], "admin" | "root">;
// "admin"
Exclude の逆で、両方に共通する型だけを取り出します。
使いどころ
- 2つの権限セットの共通部分を求める
- 既存の Union 型からサブセットを安全に切り出す
NonNullable<T> — null / undefined を除外
type ValidEmail = NonNullable<User["email"]>;
// string(undefined が除外される)
使いどころ
- オプショナルなフィールドが「存在することが確定した後」の型として
-
find()やMap.get()の結果を絞り込んだ後の型
const email: string | undefined = user.email;
if (email != null) {
// ここでは email は string 型(TSの制御フロー解析で絞られる)
// 型を明示的に表現したい場合に NonNullable が使える
sendEmail(email as NonNullable<User["email"]>);
}
まとめ
| Utility Type | ざっくり説明 | よくある用途 |
|---|---|---|
Partial<T> |
全プロパティをオプショナルに | PATCH リクエスト、部分更新 |
Required<T> |
全プロパティを必須に | バリデーション後の型 |
Readonly<T> |
全プロパティを読み取り専用に | APIレスポンスの保持 |
Pick<T, K> |
指定プロパティだけ抽出 | コンポーネントの props |
Omit<T, K> |
指定プロパティを除外 | POST リクエスト(id除外) |
Record<K, T> |
キーと値のペアを定義 | キャッシュ、ルックアップ |
Exclude<T, U> |
Unionから除外 | 「admin以外」の表現 |
Extract<T, U> |
Unionから抽出 | 共通権限の取得 |
NonNullable<T> |
null/undefined を除外 | オプショナル確定後の型 |
どれも標準で使えるので、ライブラリの追加は不要です。まずは Partial / Pick / Omit あたりから日常的に使ってみると、型定義の重複がかなり減ると思います。