Memahami Generic Constraint dan Utility Types dalam TypeScript

By | 22 October 2025

Dalam pengembangan aplikasi TypeScript, kemampuan untuk menulis kode yang fleksibel namun tetap aman menjadi hal yang sangat penting. Di sinilah Utility Types dan Generic Constraint berperan. TypeScript menawarkan fitur generik untuk membuat kode yang dapat digunakan kembali, tetapi sering kali kita perlu membatasi jenis data yang bisa digunakan. Dengan Generic Constraint, kita bisa memastikan bahwa tipe yang digunakan memenuhi syarat tertentu.

Selain itu, TypeScript menyediakan Utility Types, yaitu sekumpulan tipe bawaan yang mempermudah manipulasi tipe data kompleks tanpa harus menulis ulang struktur tipe tersebut. Penggunaan Utility Types sangat membantu dalam menjaga konsistensi dan efisiensi kode terutama pada proyek berskala besar.

Apa Itu Generic Constraint?

Generic Constraint digunakan untuk membatasi jenis data yang dapat digunakan dalam parameter generik. Tanpa constraint, parameter generik bisa menerima tipe apa pun, termasuk tipe yang tidak sesuai. Dengan menambahkan batasan menggunakan extends, kita dapat mengontrol tipe data tersebut agar sesuai dengan kebutuhan.

Contoh penggunaan Generic Constraint:

function getProperty<T extends object, K extends keyof T>(obj: T, key: K) {
  return obj[key];
}

const user = { name: "Andi", age: 25 };
console.log(getProperty(user, "name")); // Output: Andi

Dalam contoh di atas, T dibatasi dengan extends object, artinya T hanya bisa berupa objek. Kemudian K dibatasi dengan keyof T, sehingga key harus merupakan salah satu properti dari objek T.

Keuntungan Menggunakan Generic Constraint

  1. Keamanan tipe (type safety) – Mencegah kesalahan karena penggunaan tipe yang tidak sesuai.

  2. Autocompletion lebih akurat – Editor TypeScript dapat memberikan saran properti secara otomatis.

  3. Konsistensi kode – Meningkatkan keterbacaan dan meminimalkan bug dalam pengembangan jangka panjang.

Apa Itu Utility Types?

Utility Types adalah kumpulan tipe bawaan yang disediakan TypeScript untuk membantu developer memodifikasi tipe yang sudah ada tanpa menulis ulang struktur aslinya. Beberapa contoh Utility Types yang umum digunakan adalah Partial, Required, Readonly, Pick, dan Omit.

Berikut beberapa contoh implementasinya:

1. Partial<T>

Mengubah semua properti dari tipe T menjadi opsional.

interface User {
  name: string;
  age: number;
}

const updateUser = (user: Partial<User>) => {
  console.log(user);
};

updateUser({ name: "Budi" });

2. Required<T>

Kebalikan dari Partial, membuat semua properti wajib diisi.

interface Profile {
  username?: string;
  bio?: string;
}

const setProfile = (data: Required<Profile>) => {
  console.log(data.username + " - " + data.bio);
};

setProfile({ username: "Dina", bio: "Frontend Developer" });

3. Readonly<T>

Menjadikan semua properti dari tipe T hanya dapat dibaca (tidak bisa diubah).

interface Config {
  apiUrl: string;
}

const config: Readonly<Config> = { apiUrl: "https://api.example.com" };
// config.apiUrl = "https://newapi.com"; ❌ Error

4. Pick<T, K> dan Omit<T, K>

Pick digunakan untuk mengambil sebagian properti dari sebuah tipe, sedangkan Omit digunakan untuk menghilangkan properti tertentu.

interface Product {
  id: number;
  name: string;
  price: number;
  stock: number;
}

type ProductPreview = Pick<Product, "id" | "name">;
type ProductDetail = Omit<Product, "stock">;

Menggabungkan Generic Constraint dan Utility Types

Generic Constraint dan Utility Types dapat digunakan bersamaan untuk menciptakan tipe yang lebih kuat dan fleksibel.

function cloneObject<T extends object>(obj: Readonly<T>): T {
  return { ...obj };
}

const original = { id: 1, name: "Laptop" };
const clone = cloneObject(original);
console.log(clone);

Pada contoh di atas, Readonly<T> memastikan bahwa parameter obj tidak bisa dimodifikasi di dalam fungsi, sementara Generic Constraint extends object memastikan bahwa hanya tipe objek yang bisa dikloning.

Kesimpulan

Utility Types dan Generic Constraint adalah dua fitur penting dalam TypeScript yang membantu developer menulis kode yang lebih aman, efisien, dan mudah dipelihara. Dengan Generic Constraint, kita dapat membatasi tipe data agar sesuai dengan kebutuhan logika program. Sementara Utility Types mempercepat pembuatan tipe baru dari struktur yang sudah ada tanpa mengulang penulisan.

Menguasai kedua konsep ini merupakan langkah penting menuju pengembangan aplikasi TypeScript yang profesional dan scalable.