Skip to content

Utility Types

11.3.1. Built-in Utility Types

Actively use TypeScript's built-in utility types to prevent type duplication.

Utility TypeUse CaseDescription
Partial<T>Edit formsConverts all properties to optional
Required<T>Required guaranteeConverts all properties to required
Pick<T, K>Partial selectionExtracts specific properties
Omit<T, K>Property exclusionRemoves specific properties
Record<K, V>Map structureDefines key-value pair object types
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>
  • Variations derived from the same type must be generated using utility types. Do not manually copy properties.

11.3.2. API Response Type Definition Patterns

API responses must maintain a consistent structure using a generic wrapper type.

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[]>
}

// Usage example
async function fetchOrders(page: number): Promise<ApiResponse<PaginatedResponse<OrderDto>>> {
  const response = await api.get('/orders', { params: { page } })
  return response.data
}
  • All API response functions must have an explicit return type. Do not rely on type inference.

11.3.3. Generic Components

Shared components must use generics to maintain type safety.

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>

Generic composables reuse the same logic across various types.

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 and Immutability

Apply immutable types to data that must not be modified.

typescript
// Readonly — prevents object property modification
const config: Readonly<{ apiBaseUrl: string; maxRetries: number }> = {
  apiBaseUrl: 'https://api.example.com',
  maxRetries: 3,
}

// ReadonlyArray — prevents array modification
function calculateTotal(items: ReadonlyArray<{ price: number; qty: number }>): number {
  return items.reduce((sum, item) => sum + item.price * item.qty, 0)
}

// as const — fixes literal types
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
  • Apply as const to configuration objects and constant tables to preserve literal types.
  • When a function parameter receives an array that is not modified internally, use ReadonlyArray<T>.

TIENIPIA QUALIFIED STANDARD