Skip to content

ユーティリティ型

11.3.1. 基本ユーティリティ型

TypeScript 組み込みユーティリティ型を積極的に活用して、型の重複を防止します。

ユーティリティ型用途説明
Partial<T>編集フォームすべてのプロパティをオプショナルに変換
Required<T>必須保証すべてのプロパティを必須に変換
Pick<T, K>部分選択特定のプロパティのみ抽出
Omit<T, K>プロパティ除外特定のプロパティを除去
Record<K, V>マップ構造キーと値のペアによるオブジェクト型定義
typescript
interface Product { id: number; name: string; price: number; description: string }

type UpdateProductRequest = Partial<Omit<Product, 'id'>>
type ProductSummary = Pick<Product, 'id' | 'name' | 'price'>
type CategoryCount = Record<string, number>
  • 同一型から派生するバリエーションはユーティリティ型で生成します。プロパティを手動でコピーしません。

11.3.2. API レスポンス型の定義パターン

API レスポンスはジェネリックラッパー型で一貫した構造を維持します。

typescript
// src/types/common.ts
interface ApiResponse<T> {
  success: boolean
  data: T
  message: string
}

interface PaginatedResponse<T> {
  items: T[]
  page: number
  pageSize: number
  totalItems: number
  totalPages: number
}

interface ApiError {
  code: string
  message: string
  details?: Record<string, string[]>
}

// 活用例
async function fetchOrders(page: number): Promise<ApiResponse<PaginatedResponse<OrderDto>>> {
  const response = await api.get('/orders', { params: { page } })
  return response.data
}
  • すべての API レスポンス関数に戻り値の型を明示します。型推論に依存しません。

11.3.3. ジェネリックコンポーネント

共通コンポーネントはジェネリックを活用して型安全性を維持します。

vue
<script setup lang="ts" generic="T extends { id: number; label: string }">
defineProps<{ options: T[]; modelValue: T | null }>()
const emit = defineEmits<{ 'update:modelValue': [value: T] }>()
</script>

ジェネリック Composable は、さまざまな型に対して同一のロジックを再利用します。

typescript
// src/composables/useAsyncData.ts
import { ref, type Ref } from 'vue'

export function useAsyncData<T>(fetcher: () => Promise<T>) {
  const data = ref<T | null>(null) as Ref<T | null>
  const loading = ref(false)

  async function execute() {
    loading.value = true
    try { data.value = await fetcher() }
    finally { loading.value = false }
  }

  return { data, loading, execute }
}

11.3.4. Readonly と不変性

変更してはならないデータには不変型を適用します。

typescript
// Readonly — オブジェクトプロパティの変更防止
const config: Readonly<{ apiBaseUrl: string; maxRetries: number }> = {
  apiBaseUrl: 'https://api.example.com',
  maxRetries: 3,
}

// ReadonlyArray — 配列の変更防止
function calculateTotal(items: ReadonlyArray<{ price: number; qty: number }>): number {
  return items.reduce((sum, item) => sum + item.price * item.qty, 0)
}

// as const — リテラル型の固定
const HTTP_STATUS = { OK: 200, NOT_FOUND: 404, SERVER_ERROR: 500 } as const
type HttpStatusCode = (typeof HTTP_STATUS)[keyof typeof HTTP_STATUS] // 200 | 404 | 500
  • 設定オブジェクト、定数テーブルには as const を適用してリテラル型を保持します。
  • 関数パラメータとして配列を受け取る際、内部で変更しない場合は ReadonlyArray<T> を使用します。

TIENIPIA QUALIFIED STANDARD