TypeScript - Batasan Generik: Melepaskan Kekuatan Tipe Flexibel
Hai teman-teman, para ahli TypeScript masa depan! Hari ini, kita akan melanjutkan perjalanan yang menarik ke dunia Batasan Generik. Jangan khawatir jika Anda baru belajar pemrograman – saya akan menjadi panduan yang ramah, dan kita akan mengatasi topik ini langkah demi langkah. Pada akhir panduan ini, Anda akan bisa membatasi generik seperti seorang ahli!
Apa Itu Batasan Generik?
Sebelum kita masuk ke hal yang lebih rinci, mari kita mulai dengan analogi sederhana. Bayangkan Anda memiliki sebuah kotak ajaib yang dapat menampung jenis item apa pun. Itu sebenarnya apa yang dimaksudkan oleh generik di TypeScript – sebuah wadah fleksibel untuk jenis-jenis yang berbeda. Sekarang, bagaimana jika kita ingin menetapkan beberapa aturan tentang apa yang bisa dimasukkan ke dalam kotak itu? Itu di mana batasan generik memainkan perannya!
Batasan generik memungkinkan kita untuk membatasi jenis yang dapat digunakan dengan generik kita. Itu seperti memberi label pada kotak ajaib kita yang mengatakan, "Hanya objek dengan properti 'length' yang diperbolehkan!"
Contoh Masalah: Mengapa Kita Butuh Batasan Generik?
Marilah kita lihat beberapa konteks di mana batasan generik dapat menyelamatkan hari:
Contoh 1: Properti Panjang yang Misterius
function getLength<T>(item: T): number {
return item.length; // Error: Properti 'length' tidak ada pada tipe 'T'
}
Ups! TypeScript memberikan kita kesalahan. Mengapa? Karena tidak semua jenis memiliki properti length
. Apa bila kita mengirimkan bilangan ke fungsi ini? Bilangan tidak memiliki panjang!
Contoh 2: Perbandingan yang Membingungkan
function compareValues<T>(value1: T, value2: T): boolean {
return value1 > value2; // Error: Operator '>' tidak dapat diterapkan ke jenis 'T' dan 'T'
}
Kesalahan lagi! TypeScript tidak tahu jika T
dapat dibandingkan menggunakan >
. Apa bila kita mengirimkan string? Atau objek kompleks?
Contoh ini menunjukkan kepada kita mengapa kita butuh batasan generik. Mereka membantu kita menulis kode yang lebih presisi dan bebas dari kesalahan.
Bagaimana Batasan Generik Bekerja di TypeScript
Sekarang, mari kita lihat bagaimana kita dapat menggunakan batasan generik untuk memecahkan masalah kita:
Kata Ajaib extends
Untuk menambahkan batasan, kita menggunakan kata kunci extends
. Itu seperti memberitahu TypeScript, "Hey, jenis ini harus memiliki setidaknya properti atau kemampuan ini!"
mari kita perbaiki fungsi getLength
:
interface Lengthwise {
length: number;
}
function getLength<T extends Lengthwise>(item: T): number {
return item.length; // Tidak ada kesalahan lagi!
}
Sekarang, mari kitauraikan ini:
- Kita mendefinisikan sebuah interface
Lengthwise
yang memiliki propertilength
. - Kita gunakan
<T extends Lengthwise>
untuk mengatakan "T harus memiliki setidaknya apa yang ada di Lengthwise". - Sekarang TypeScript tahu bahwa apa pun
T
itu, ia pasti akan memiliki propertilength
!
Mari kita cobalah:
console.log(getLength("Hello")); // Bekerja! String memiliki panjang
console.log(getLength([1, 2, 3])); // Bekerja! Array memiliki panjang
console.log(getLength(123)); // Kesalahan! Bilangan tidak memiliki panjang
Apakah itu menakjubkan? Kita telah berhasil membatasi generik kita!
Menggunakan Parameter Tipe dalam Batasan Generik
kadang-kadang, kita ingin membatasi satu parameter tipe berdasarkan yang lain. Itu seperti mengatakan, "Kotak ini hanya dapat menampung item yang kompatibel dengan apa yang sudah ada di dalamnya."
Marilah kita lihat contoh:
function copyProperties<T extends U, U>(target: T, source: U): T {
for (let id in source) {
target[id] = source[id];
}
return target;
}
Apa yang terjadi disini?
- Kita memiliki dua parameter tipe:
T
danU
. -
T extends U
berartiT
harus setidaknya semua yangU
adalah, tetapi bisa memiliki lebih. - Ini memungkinkan kita untuk menyalin properti dari
source
ketarget
, dengan mengetahui bahwatarget
akan memiliki semua properti yang ada disource
.
Mari kita lihatnya dalam aksi:
interface Person {
name: string;
}
interface Employee extends Person {
employeeId: number;
}
let person: Person = { name: "Alice" };
let employee: Employee = { name: "Bob", employeeId: 123 };
copyProperties(employee, person); // Bekerja!
copyProperties(person, employee); // Kesalahan! Person tidak memiliki employeeId
Aplikasi Praktis dan Praktik Terbaik
Sekarang kita mengerti bagaimana batasan generik bekerja, mari kita lihat beberapa aplikasi dunia nyata dan praktik terbaik:
- Batasan ke Tipe Objek: Seringkali, Anda ingin memastikan Anda bekerja dengan objek:
function cloneObject<T extends object>(obj: T): T {
return { ...obj };
}
- Batasan ke Tipe Fungsi: Anda dapat memastikan jenis adalah panggilan:
function invokeFunction<T extends Function>(func: T): void {
func();
}
- Batasan ke Properti tertentu: Memastikan objek memiliki properti tertentu:
function getFullName<T extends { firstName: string; lastName: string }>(obj: T): string {
return `${obj.firstName} ${obj.lastName}`;
}
-
Batasan Ganda: Anda dapat menerapkan batasan ganda menggunakan operator
&
:
function processData<T extends number & { toFixed: Function }>(data: T): string {
return data.toFixed(2);
}
Berikut adalah tabel yang menggabungkan metode ini:
Metode | Deskripsi | Contoh |
---|---|---|
Batasan Objek | Memastikan jenis adalah objek | <T extends object> |
Batasan Fungsi | Memastikan jenis dapat dipanggil | <T extends Function> |
Batasan Properti | Memastikan jenis memiliki properti tertentu | <T extends { prop: Type }> |
Batasan Ganda | Menggabungkan batasan ganda | <T extends TypeA & TypeB> |
Kesimpulan: Mengakui Kekuatan Batasan
Selamat! Anda baru saja membuka kunci alat yang kuat di dalam kotak alat TypeScript Anda. Batasan generik memungkinkan kita menulis kode yang fleksibel tetapi aman, memberikan kita kebaikan terbaik dari kedua dunia.
Ingat, kunci untuk menguasai batasan generik adalah latihan. Cobalah merefactorkan beberapa kode Anda yang ada untuk menggunakan generik dan batasan. Anda akan terkejut melihat betapa bersih dan kuat kode Anda menjadi!
Sebagai penutup, ini adalah sedikit humor pemrograman untuk Anda: Mengapa pengembang TypeScript bangkrut? Karena dia menggunakan terlalu banyak batasan generik dan tidak dapat menerima jenis pembayaran apa pun! ?
Tetap mengoding, tetap belajar, dan terutama, bersenang-senang dengan TypeScript!
Credits: Image by storyset