TypeScriptのユーティリティ型(Partial・Pick・Omit・ReturnTypeなど)を整理した話

TypeScriptには型を変換・加工するユーティリティ型が組み込まれています。SvelteKitのコードでも頻繁に使います。


Partial — 全プロパティを省略可能にする

type Post = {
  id: number;
  title: string;
  body: string;
};

type PartialPost = Partial<Post>;
// { id?: number; title?: string; body?: string; }

実務での使い場面: 更新フォームで「変更したフィールドだけ送る」とき。

async function updatePost(id: number, updates: Partial<Post>) {
  // title だけ・body だけの更新が可能
}

Required — 全プロパティを必須にする

type DraftPost = {
  title?: string;
  body?: string;
};

type PublishedPost = Required<DraftPost>;
// { title: string; body: string; }

Pick — 特定のプロパティだけ抽出する

type Post = {
  id: number;
  title: string;
  body: string;
};

// 一覧表示用(body は不要)
type PostSummary = Pick<Post, 'id' | 'title'>;
// { id: number; title: string; }

実務での使い場面: 一覧APIでは全フィールドを返さず必要なものだけに絞るとき。

// SELECT id, title FROM posts → PostSummary 型で受け取る
const result = await db.prepare('SELECT id, title FROM posts')
  .all<PostSummary>();

Omit — 特定のプロパティを除外する

// 新規作成フォーム用(id は自動採番なので不要)
type NewPost = Omit<Post, 'id'>;
// { title: string; body: string; }

// 更新フォーム用(id は変更不要 + 変更したいフィールドだけ送る)
type UpdatePost = Partial<Omit<Post, 'id'>>;
// { title?: string; body?: string; }

Pick の逆です。「これ以外を残したい」ときは Omit が便利です。


ReturnType — 関数の戻り値の型を取得する

function createUser() {
  return {
    id: crypto.randomUUID(),
    name: 'ゲスト',
    createdAt: new Date(),
  };
}

type User = ReturnType<typeof createUser>;
// { id: string; name: string; createdAt: Date; }

実務での使い場面: load 関数の戻り値の型を使い回すとき。

// +page.server.ts の load の戻り値を型として使う
type PageData = Awaited<ReturnType<typeof load>>;

Awaited — Promiseの中の型を取り出す

type Result = Awaited<Promise<string>>;
// string

async function fetchPost() {
  return { id: 1, title: '記事' };
}

type Post = Awaited<ReturnType<typeof fetchPost>>;
// { id: number; title: string; }

ReturnType と組み合わせて、async関数の戻り値の型を取り出すときによく使います。


Record — キーと値の型を指定したオブジェクト型

// キーが string、値が number のオブジェクト
type ScoreMap = Record<string, number>;
// { [key: string]: number }

// キーを列挙型に限定する
type CategoryCount = Record<'tech' | 'life' | 'work', number>;
// { tech: number; life: number; work: number; }

SvelteKitでよく使う組み合わせ

// src/lib/posts.ts
export type Post = {
  id: number;
  title: string;
  body: string;
};

// 新規作成フォーム用(id は自動採番なので不要)
export type NewPost = Omit<Post, 'id'>;

// 更新フォーム用(変更したいフィールドだけ送れるように)
export type UpdatePost = Partial<Omit<Post, 'id'>>;

// 一覧表示用(body は不要)
export type PostSummary = Pick<Post, 'id' | 'title'>;

元の型から派生した型を作ることで、Post の定義を変えたときに派生型も自動で追従します。


型が効いているかの確認方法

エディタ上でエラーが出ることで型が正しく効いているか確認できます。

const body = await request.json() as NewPost;

// ❌ NewPost に id は存在しないのでTypeScriptエラーになる
console.log(body.id);

// ✅ これはOK
console.log(body.title);
console.log(body.body);

まとめ

ユーティリティ型 内容 使い場面
Partial<T> 全プロパティを省略可能に 更新フォーム
Required<T> 全プロパティを必須に 省略可能な型を確定させる
Pick<T, K> 特定のプロパティだけ抽出 一覧表示・フォーム
Omit<T, K> 特定のプロパティを除外 新規作成フォーム
ReturnType<T> 関数の戻り値の型を取得 load関数の戻り値
Awaited<T> Promiseの中の型を取り出す async関数と組み合わせて
Record<K, V> キーと値の型を指定したオブジェクト マップ型のデータ
← トップページに戻る