Utility Types
11.3.1. Built-in Utility Types
Actively use TypeScript's built-in utility types to prevent type duplication.
| Utility Type | Use Case | Description |
|---|---|---|
Partial<T> | Edit forms | Converts all properties to optional |
Required<T> | Required guarantee | Converts all properties to required |
Pick<T, K> | Partial selection | Extracts specific properties |
Omit<T, K> | Property exclusion | Removes specific properties |
Record<K, V> | Map structure | Defines 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 constto configuration objects and constant tables to preserve literal types. - When a function parameter receives an array that is not modified internally, use
ReadonlyArray<T>.