TypeScript ユーティリティ型マスターガイド:Partial、Pick、Omit の実践的活用法

TypeScript のユーティリティ型は、日々の開発現場で「型の柔軟性」と「型安全性」を両立させるための強力な武器です。この記事では、Partial、Pick、Omit を中心に、実務で役立つ活用法や設計パターンを徹底解説します。
ユーティリティ型とは何か
ユーティリティ型(Utility Types)とは、既存の型をもとに新しい型を簡単に生成できる TypeScript の組み込み型のことです。型の再利用性や保守性を高め、冗長な型定義を減らすことができます。
代表的なユーティリティ型には、Partial
、Pick
、Omit
、Required
、Readonly
、Record
などがありますが、今回は特に現場での利用頻度が高い 3 つに絞って解説します。
Partial、Pick、Omit の基本と使い分け
Partial の使い方と注意点
Partial<T>
は、型 T のすべてのプロパティを「オプショナル(省略可能)」にした新しい型を作ります。
typescriptinterface User {
id: number;
name: string;
email: string;
}
// Partialを使うと全プロパティがオプショナルに
const updateUser = (user: Partial<User>) => {
// id, name, email どれも省略可能
};
updateUser({ name: '新しい名前' }); // OK
注意点:
- すべてのプロパティが省略可能になるため、必須項目のバリデーションは別途必要です。
- ネストしたオブジェクトのプロパティまではオプショナルになりません(再帰的 Partial は後述)。
Pick の使い方と注意点
Pick<T, K>
は、型 T から指定したプロパティ K だけを抜き出した新しい型を作ります。
typescripttype UserNameAndEmail = Pick<User, 'name' | 'email'>;
const userInfo: UserNameAndEmail = {
name: '田中',
email: 'tanaka@example.com',
};
注意点:
- 存在しないプロパティ名を指定するとコンパイルエラーになります。
- プロパティ名はリテラル型またはユニオン型で指定します。
Omit の使い方と注意点
Omit<T, K>
は、型 T から指定したプロパティ K を「除外」した新しい型を作ります。
typescripttype UserWithoutEmail = Omit<User, 'email'>;
const user: UserWithoutEmail = {
id: 1,
name: '佐藤',
};
注意点:
- Pick と同様、存在しないプロパティ名を指定するとエラーになります。
- Omit は「一部だけ除外したい」場合に便利です。
よくある業務シナリオでの活用例
フォームバリデーション
フォームの「部分更新」や「バリデーション」では、Partial 型が大活躍します。
typescript// ユーザー情報の部分更新フォーム
function validateUserInput(input: Partial<User>) {
if (input.email && !input.email.includes('@')) {
throw new Error('メールアドレスの形式が不正です');
}
}
API リクエスト・レスポンス型の変換
API のリクエストやレスポンスで、必要なフィールドだけを抽出したい場合は Pick や Omit が便利です。
typescript// 新規ユーザー作成API(idは不要)
type CreateUserRequest = Omit<User, 'id'>;
// ユーザー一覧取得API(emailは返さない)
type UserListItem = Omit<User, 'email'>;
// プロフィール表示用(nameとemailのみ)
type UserProfile = Pick<User, 'name' | 'email'>;
データ更新・パッチ処理
PATCH API や部分的なデータ更新では、Partial と Omit を組み合わせることで柔軟な型設計が可能です。
typescript// id以外のプロパティを部分的に更新
function patchUser(
id: number,
update: Partial<Omit<User, 'id'>>
) {
// updateはname/emailのどちらか、または両方を含む可能性がある
}
patchUser(1, { name: '新しい名前' });
ユーティリティ型を組み合わせた高度な型設計
ユーティリティ型は組み合わせて使うことで、より柔軟で型安全な設計が可能です。
typescript// 例:一部のプロパティだけをオプショナルにしたい
interface Product {
id: number;
name: string;
price: number;
description?: string;
}
type ProductUpdate = Partial<
Pick<Product, 'name' | 'price'>
> &
Pick<Product, 'id'>;
const update: ProductUpdate = {
id: 1,
price: 2000, // nameは省略可能
};
また、Omit や Pick をネストして使うことで、複雑な型変換もシンプルに記述できます。
typescript// 例:User型からidとemailを除外し、残りをオプショナルに
// → nameだけがオプショナルな型
type NameOptional = Partial<Omit<User, 'id' | 'email'>>;
カスタムユーティリティ型の作り方
標準のユーティリティ型だけでは足りない場合、自作の型を作ることもできます。
typescript// 再帰的Partial型(ネストしたプロパティもオプショナルに)
type DeepPartial<T> = {
[P in keyof T]?: T[P] extends object
? DeepPartial<T[P]>
: T[P];
};
interface NestedUser {
id: number;
profile: {
name: string;
address: {
city: string;
};
};
}
const user: DeepPartial<NestedUser> = {
profile: {
address: {},
},
};
また、条件付き型や Mapped Types を使えば、独自の Pick/Omit バリエーションも作成可能です。
typescript// 例:特定の型のプロパティだけを抽出するPickByType
type PickByType<T, U> = {
[K in keyof T as T[K] extends U ? K : never]: T[K];
};
interface Example {
id: number;
name: string;
isActive: boolean;
}
type BooleanProps = PickByType<Example, boolean>; // { isActive: boolean }
型安全性を高めるためのベストプラクティス
- 冗長な型定義を避ける:ユーティリティ型で共通部分を抽出し、重複を減らす
- Partial の使いすぎに注意:本当に省略可能な場合だけ使う
- Pick/Omit で API 契約を明確に:必要なフィールドだけを明示的に指定する
- カスタム型で現場の要件に柔軟対応:標準型で足りない場合は自作型を活用
- 型の再利用性を意識する:一度作った型は積極的に再利用
- 型のテストも忘れずに:型テスト用のユーティリティや型レベルテストも活用
まとめ:ユーティリティ型を使いこなすコツ
TypeScript のユーティリティ型は、現場の「型設計」を劇的に効率化してくれる頼もしい存在です。Partial、Pick、Omit を使いこなすことで、柔軟かつ堅牢な型設計が可能になります。カスタム型や組み合わせテクニックも駆使し、型安全な開発を楽しみましょう!
関連リンク
- blog
「アジャイルコーチ」って何する人?チームを最強にする影の立役者の役割と、あなたがコーチになるための道筋
- blog
ペアプロって本当に効果ある?メリットだけじゃない、現場で感じたリアルな課題と乗り越え方
- blog
TDDって結局何がいいの?コードに自信が持てる、テスト駆動開発のはじめの一歩
- blog
「昨日やったこと、今日やること」の報告会じゃない!デイリースクラムをチームのエンジンにするための3つの問いかけ
- blog
燃え尽きるのは誰だ?バーンダウンチャートでプロジェクトの「ヤバさ」をチームで共有する方法
- blog
「誰が、何を、なぜ」が伝わらないユーザーストーリーは無意味。開発者が本当に欲しいストーリーの書き方