Typescript Utility Types Type Composition Inference Helpers Type Safe API Response Patterns
Definisi
Utility Types adalah tipe bawaan TypeScript yang mengubah tipe lain menjadi bentuk baru (misal Partial, Pick, Omit, Record). Type composition adalah menyusun tipe kecil menjadi tipe domain yang utuh, sehingga tipe tetap readable dan mudah dirawat.
Kapan dipakai
Pakai Utility Types tiap kali kamu perlu varian dari tipe yang sudah ada: form draft (Partial), response API (Omit field internal), map key-value (Record). Jangan menulis ulang tipe secara manual tiap kali butuh sedikit perubahan.
Cara kerja
Utility Types umum
type User = {
id: string;
name: string;
email: string;
passwordHash: string;
};
type UserDraft = Partial<User>; // semua field opsional
type PublicUser = Omit<User, 'passwordHash'>; // buang field rahasia
type UserCard = Pick<User, 'id' | 'name'>; // ambil sebagian
type UsersById = Record<string, User>; // map id -> UserType composition
Gabungkan tipe lewat intersection (&):
type Timestamps = {
createdAt: string;
updatedAt: string;
};
type UserEntity = User & Timestamps;Inference helper
Buat helper yang menyimpulkan tipe dari nilai:
function asConst<T extends string>(values: readonly T[]) {
return values;
}
const ROLES = asConst(['admin', 'editor', 'viewer']);
type Role = typeof ROLES[number]; // 'admin' | 'editor' | 'viewer'Type-safe API response
type ApiResponse<T> =
| { ok: true; data: T }
| { ok: false; error: string };
async function getJSON<T>(url: string): Promise<ApiResponse<T>> {
const res = await fetch(url);
if (!res.ok) {
return { ok: false, error: res.statusText };
}
return { ok: true, data: (await res.json()) as T };
}Caller wajib menangani kedua cabang:
const r = await getJSON<PublicUser>('/api/me');
if (r.ok) {
console.log(r.data.name); // aman
} else {
console.error(r.error);
}Struktur alur komposisi
Catatan implementasi
- Utamakan
Omit/Pickdaripada menulis ulang tipe, supaya perubahan field di sumber ikut terbawa. - Untuk response API, pakai discriminated union (
ok: true | false) supaya caller tidak lupa menangani error. Record<string, T>lebih aman dari{ [key: string]: T }karena konsisten dan lebih ringkas.
Kesalahan umum
- Over-abstracting: membuat utility type generic berlapis yang malah menyulitkan pembacaan.
- Manual duplicate type: menulis ulang tipe response padahal cukup
Omit, sehingga kalau field berubah jadi tidak sinkron. - Lupa narrow union: mengakses
r.datatanpa cekr.ok, padahal bisa undefined di cabang error. anysebagai shortcut: menghilangkan manfaat type-safe padahalunknown+ narrowing lebih aman.