Dalam pengembangan aplikasi besar menggunakan TypeScript, pengelolaan tipe data menjadi faktor penting untuk menjaga konsistensi dan keandalan kode. Di sinilah advanced types berperan besar — mereka memungkinkan developer menulis kode yang lebih fleksibel, efisien, dan tetap aman dari kesalahan tipe. Dengan memahami konsep ini, kamu dapat mengoptimalkan kekuatan sistem tipe yang dimiliki TypeScript.
Selain itu, TypeScript menyediakan berbagai utility types bawaan seperti Partial, Pick, Omit, Record, dan Readonly yang sangat membantu dalam manipulasi struktur tipe tanpa menulis ulang deklarasi tipe dari awal. Pada artikel ini, kita akan membahas advanced types dan penggunaannya dalam berbagai skenario, termasuk conditional types dan mapped types untuk membuat tipe dinamis yang kuat dan adaptif.
Apa Itu Advanced Types?
Advanced types adalah fitur lanjutan dalam TypeScript yang memungkinkan kita membuat tipe data kompleks dari kombinasi tipe yang sudah ada. Tujuannya adalah untuk memberikan fleksibilitas tinggi tanpa kehilangan keamanan tipe (type safety).
Beberapa fitur penting yang masuk kategori ini termasuk utility types, mapped types, dan conditional types, yang akan kita bahas lebih mendalam di bawah.
Utility Types dalam TypeScript
Utility types adalah tipe bawaan (built-in) yang disediakan TypeScript untuk mempermudah manipulasi tipe objek. Berikut beberapa utility types yang paling umum digunakan:
1. Partial<T>
Mengubah semua properti dari sebuah tipe menjadi optional.
interface Product {
id: number;
name: string;
price: number;
}
type PartialProduct = Partial<Product>;
const updateData: PartialProduct = {
name: "Produk Baru"
};
2. Pick<T, K>
Mengambil sebagian properti dari sebuah tipe.
type ProductInfo = Pick<Product, "id" | "name">;
const data: ProductInfo = {
id: 1,
name: "Laptop"
};
3. Omit<T, K>
Kebalikan dari Pick, digunakan untuk menghapus beberapa properti dari tipe.
type ProductWithoutPrice = Omit<Product, "price">;
4. Record<K, T>
Membuat objek dengan key K dan tipe nilai T.
type Stock = Record<string, number>;
const inventory: Stock = {
"Laptop": 10,
"Mouse": 25
};
5. Readonly<T>
Menjadikan semua properti tidak dapat diubah (immutable).
const product: Readonly<Product> = {
id: 1,
name: "Monitor",
price: 200
};
// product.price = 250; ❌ Error
Conditional Types (extends ? :)
Conditional types memungkinkan kita membuat tipe dinamis yang berubah tergantung pada kondisi tertentu.
type IsString<T> = T extends string ? "String" : "Not String"; type A = IsString<string>; // "String" type B = IsString<number>; // "Not String"
Ini sangat berguna untuk membuat tipe adaptif berdasarkan input generik.
Mapped Types
Mapped types digunakan untuk memodifikasi atau membuat ulang tipe berdasarkan tipe lain. Mereka sering digunakan dalam pembuatan utility types bawaan.
Contoh sederhana:
type Optional<T> = {
[K in keyof T]?: T[K];
};
type OptionalProduct = Optional<Product>;
Kita bisa mengombinasikannya dengan conditional types untuk menciptakan tipe yang lebih dinamis dan cerdas.
Contoh Real: Validasi Data Otomatis
Bayangkan kita ingin membuat sistem validasi data produk. Dengan utility dan advanced types, kita bisa menentukan tipe data yang fleksibel:
type ValidationRules<T> = {
[K in keyof T]?: (value: T[K]) => boolean;
};
const productRules: ValidationRules<Product> = {
name: val => val.length > 0,
price: val => val > 0
};
Dengan pendekatan ini, kita dapat membuat sistem validasi yang aman dan efisien tanpa kehilangan dukungan tipe yang kuat.
Kesimpulan
Pemahaman advanced types dan utility types seperti Partial, Pick, Omit, Record, dan Readonly akan membuatmu semakin produktif dalam menulis kode TypeScript. Ditambah dengan konsep conditional types dan mapped types, kamu bisa membangun sistem tipe yang dinamis, kuat, dan tetap aman.
Dengan menguasai fitur ini, kamu akan melangkah lebih jauh dari sekadar menulis TypeScript dasar — kamu akan menulis kode yang efisien, scalable, dan siap digunakan di proyek besar.