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!

TypeScript - Generic Constraints

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:

  1. Kita mendefinisikan sebuah interface Lengthwise yang memiliki properti length.
  2. Kita gunakan <T extends Lengthwise> untuk mengatakan "T harus memiliki setidaknya apa yang ada di Lengthwise".
  3. Sekarang TypeScript tahu bahwa apa pun T itu, ia pasti akan memiliki properti length!

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?

  1. Kita memiliki dua parameter tipe: T dan U.
  2. T extends U berarti T harus setidaknya semua yang U adalah, tetapi bisa memiliki lebih.
  3. Ini memungkinkan kita untuk menyalin properti dari source ke target, dengan mengetahui bahwa target akan memiliki semua properti yang ada di source.

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:

  1. Batasan ke Tipe Objek: Seringkali, Anda ingin memastikan Anda bekerja dengan objek:
function cloneObject<T extends object>(obj: T): T {
return { ...obj };
}
  1. Batasan ke Tipe Fungsi: Anda dapat memastikan jenis adalah panggilan:
function invokeFunction<T extends Function>(func: T): void {
func();
}
  1. 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}`;
}
  1. 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