Utility Types — TypeScript

TypeScript menyediakan utility types bawaan: Partial — semua property jadi opsional: interface User { nama: string; umur: number; } type PartialUser =…

Utility type adalah tipe bawaan TypeScript yang membuat tipe baru dari tipe yang sudah ada. Kamu cukup menulis User sekali, lalu Partial<User>, Pick<User, ...>, atau Omit<User, ...> menurunkan versi lain darinya. Mirip memfotokopi formulir: dari satu formulir asli kamu bisa bikin salinan yang semua kolomnya boleh kosong, salinan yang cuma berisi dua kolom, atau salinan tanpa kolom tertentu. Formulir aslinya gak berubah.

🧪 Tebakan cepat: objek kosong {} boleh disimpan sebagai User? Kalau sebagai Partial<User>? Tebak dulu, jawabannya ada di bagian "Partial dan Required".

Semua contoh di bawah memakai interface ini:

interface User {
  id: number;
  nama: string;
  email: string;
  umur?: number; // opsional
}

Utility type ditulis dengan kurung siku lancip < >, sama seperti generic, karena memang generic: User dikirim sebagai type parameter-nya.

Partial dan Required

Partial<T> membuat semua properti opsional. Required<T> kebalikannya: semua properti jadi wajib, termasuk yang tadinya pakai ?.

// Partial<User> sama dengan { id?: number; nama?: string; email?: string; umur?: number }
const kosong: Partial<User> = {}; // lolos
const salah: User = {};           // error
error TS2739: Type '{}' is missing the following properties from type 'User': id, nama, email

{} lolos sebagai Partial<User> tapi ditolak sebagai User, karena id, nama, dan email wajib. Itu jawaban tebakannya. Partial cocok untuk data update yang cuma mengubah sebagian, misalnya { email: "[email protected]" }.

// Required<User> sama dengan { id: number; nama: string; email: string; umur: number }
const lengkap: Required<User> = { id: 1, nama: "Budi", email: "[email protected]" }; // error
error TS2741: Property 'umur' is missing in type '{ id: number; nama: string; email: string; }' but required in type 'Required<User>'.

Pick dan Omit

Pick<T, K> mengambil properti tertentu saja. Omit<T, K> kebalikannya: membuang properti tertentu dan menyimpan sisanya. K adalah union nama properti, seperti hasil keyof.

type KartuProfil = Pick<User, "nama" | "email">;
// sama dengan { nama: string; email: string }

type FormDaftar = Omit<User, "id">;
// sama dengan { nama: string; email: string; umur?: number }

const form: FormDaftar = { id: 1, nama: "Budi", email: "[email protected]" }; // error
error TS2353: Object literal may only specify known properties, and 'id' does not exist in type 'Omit<User, "id">'.

Readonly dan Record

Readonly<T> membuat semua properti gak bisa diubah setelah objeknya dibuat:

const admin: Readonly<User> = { id: 1, nama: "Budi", email: "[email protected]" };
admin.nama = "Ani"; // error
error TS2540: Cannot assign to 'nama' because it is a read-only property.

Record<K, V> membuat object dengan kunci bertipe K dan nilai bertipe V:

type Nama = "budi" | "ani" | "rina";
const skor: Record<Nama, number> = { budi: 7, ani: 7, rina: 7 }; // ketiga nama wajib ada

const nilai: Record<string, number> = {}; // kunci teks apa pun, nilainya number
nilai["budi"] = 0;
nilai["ani"] = 0; // nilai sekarang { budi: 0, ani: 0 }

⚠️ Jebakan yang sering ketemu

TL;DR: Utility type membuat tipe baru dari tipe yang ada. Partial<User> membuat semua properti opsional (jadi {} lolos), Required<User> membuat semuanya wajib, dan Readonly<User> membuatnya gak bisa diubah. Pick<User, "nama" | "email"> mengambil properti tertentu, Omit<User, "id"> membuangnya, kebalikan dari Pick. Record<K, V> adalah object dengan kunci K dan nilai V, misalnya Record<string, number> untuk skor per nama seperti { budi: 0, ani: 0 }.

Yang akan kamu pelajari