Pelajari pola Singleton di TypeScript: definisi singkat, kapan cocok digunakan, contoh implementasi type-safe, dan alternatif modern seperti dependency injection untuk meningkatkan testabilitas dan maintainability.
January 19, 2026 (8mo ago) — last updated August 19, 2026 (1mo ago)
Menguasai Pola Singleton di TypeScript
Panduan praktis pola Singleton di TypeScript: kapan digunakan, contoh ConfigManager type-safe, trade-off, dan langkah refaktor menuju dependency injection.
← Back to blog
Menguasai Pola Desain Singleton: Panduan Lengkap untuk Pengembang

Dalam dunia pengembangan perangkat lunak, beberapa alat sangat kuat tetapi harus ditangani dengan hati-hati. Pola Singleton memastikan sebuah kelas hanya memiliki satu instance dan menyediakan satu cara global untuk mengaksesnya.1
Bayangkan pengelola konfigurasi pusat atau layanan logging khusus untuk seluruh aplikasi Anda. Anda tidak ingin ada beberapa objek konfigurasi yang saling bertentangan atau entri log tersebar oleh instance logger yang bersaing. Singleton membantu mencegah duplikasi, menghemat memori, dan menjaga keteraturan saat mengelola sumber daya bersama.
Apa itu Singleton dan Kapan Berguna?
Bayangkan sebuah kerajaan dengan hanya satu Juru Tulis Kerajaan. Orang ini adalah satu-satunya yang berwenang mencatat dekrit, sehingga semua catatan konsisten. Prinsip yang sama berlaku pada pola Singleton: batasi sebuah kelas sehingga hanya satu objek yang bisa dibuat, lalu jadikan instance itu sumber kebenaran yang dapat diakses dari mana saja.
Tujuan Inti dan Analogi
Singleton bukan sekadar mencegah pembuatan objek baru; ini memusatkan kontrol. Sama seperti Juru Tulis Kerajaan menyediakan satu titik akses ke catatan resmi, sebuah instance Singleton menawarkan gerbang universal ke sumber daya bersama. Contoh klasik: koneksi pool basis data—Anda tidak ingin setiap komponen membuka banyak koneksi terpisah yang menguras sumber daya.
Ide inti sederhana namun kuat: satu kelas, satu instance, satu titik akses global.
Ringkasan Karakteristik
- Single instance: kelas didesain agar hanya memiliki satu instance, biasanya dengan konstruktor private.
- Global access point: metode static seperti getInstance() memberi cara terpadu untuk mengakses instance.
- Lazy initialization: instance dibuat saat pertama kali diminta, bukan saat startup.
- Centralized state: bertindak sebagai lokasi terpusat untuk state global tertentu.
Kasus Penggunaan Praktis
Singleton berguna saat sebuah sumber daya memang unik dalam sistem:
- Layanan logging pusat.
- Manajemen konfigurasi aplikasi.
- Antarmuka perangkat keras tunggal.
Manfaat dan Kekurangan Singleton

Manfaat
- Titik akses global menyederhanakan penggunaan antar modul.
- Lazy initialization mengurangi biaya startup.
- Mengurangi duplikasi instance yang mahal.
Kekurangan
- Tight coupling: kelas dapat menyembunyikan dependensi melalui state global.
- Global state: perubahan bersama bisa menyebabkan bug sulit dilacak.
- Side effects tersembunyi: dependensi tidak tampak di tanda tangan metode, menyulitkan penalaran dan pengujian.
Dampak pada Pengujian dan Coupling
Singleton memperumit unit testing karena memperkenalkan state global yang persisten. Tes berisiko bocor state antar run, dan mem-mock Singleton bisa canggung. Tim modern sering memilih dependency injection karena membuat dependensi eksplisit dan mudah diganti saat pengujian.3
Menyeimbangkan Trade-Offs
Timbang kenyamanan versus keterpeliharaan jangka panjang. Untuk basis kode legacy, refaktor bertahap menuju dependency injection sering menjadi jalan paling aman: pertahankan perilaku sambil mengurangi coupling tersembunyi dan meningkatkan kemampuan pengujian.
Implementasi Singleton yang Aman di TypeScript
Mari beralih ke implementasi praktis yang type-safe di TypeScript. Kuncinya adalah konstruktor private dan properti static sebagai penjaga gerbang, sehingga tidak ada bagian aplikasi yang bisa membuat instance baru selain metode yang Anda kontrol.2
Contoh ConfigManager yang Type-Safe
class ConfigManager {
private static instance: ConfigManager;
private settings: Map<string, any> = new Map();
private constructor() {
console.log("Initializing ConfigManager instance...");
this.settings.set("API_URL", "https://api.example.com");
this.settings.set("TIMEOUT", 5000);
}
public static getInstance(): ConfigManager {
if (!ConfigManager.instance) {
ConfigManager.instance = new ConfigManager();
}
return ConfigManager.instance;
}
public get(key: string): any {
return this.settings.get(key);
}
}
Konstruktor private dan properti static sederhana ini efektif untuk banyak kebutuhan konfigurasi yang tidak kompleks.
Menggunakan Singleton dalam Layanan
class ApiService {
private apiUrl: string;
constructor() {
const config = ConfigManager.getInstance();
this.apiUrl = config.get("API_URL");
console.log(`ApiService initialized with API URL: ${this.apiUrl}`);
}
public fetchData(): void {
console.log(`Fetching data from ${this.apiUrl}...`);
// Real data-fetching logic would live here.
}
}
console.log("Application starting...");
const service1 = new ApiService();
service1.fetchData();
const service2 = new ApiService();
console.log("Application finished.");
Saat dijalankan, Anda akan melihat inisialisasi ConfigManager hanya sekali, membuktikan kedua service menggunakan instance yang sama.
Mengapa Singleton Kerap Dikritik
Pola ini menarik karena sederhana, tapi masalah muncul dari coupling tersembunyi, state global, dan kesulitan pengujian. Kelas yang diam-diam meraih instance global menyembunyikan dependensi yang seharusnya eksplisit di konstruktor, sehingga sistem jadi lebih sulit dipahami dan diuji.3
Masalah Konkurensi dan Global State
Singleton dengan state bersama dapat memicu kondisi balapan pada skenario konkuren. Contoh: dua permintaan simultan menaikkan counter session yang sama tanpa sinkronisasi, menghasilkan hasil tidak konsisten.
Persoalan Pengujian
Singleton membuat unit test rentan karena state dapat bocor antar tes dan mocking jadi sulit. Untuk itu tim sering mengadopsi dependency injection agar dependensi bisa dimock dengan mudah saat pengujian.
Alternatif Modern: Dependency Injection dan IoC
Dependency injection (DI) membuat dependensi eksplisit dan meningkatkan kemampuan pengujian serta modularitas. Dengan menerima dependensi lewat konstruktor, komponen menjadi mudah diuji dan lebih fleksibel.
Contoh API Service dengan DI
interface IConfigManager {
get(key: string): any;
}
class ApiService {
private apiUrl: string;
constructor(config: IConfigManager) {
this.apiUrl = config.get("API_URL");
}
}
Sekarang ApiService bergantung pada kontrak IConfigManager. Saat pengujian, Anda dapat mengoper fake atau mock, sehingga tes menjadi lebih cepat dan deterministik.
Dengan inversion of control, komponen menjadi lebih fokus dan fleksibel—inti dari Dependency Inversion Principle.
Peran IoC Container
Framework populer seperti NestJS dan Angular menyediakan DI bawaan, sementara InversifyJS populer untuk proyek TypeScript umum. Container mengelola lifecycle objek (transient, scoped, singleton) tanpa coupling tersembunyi dari Singleton programatik.56
Refaktor Singleton di Basis Kode Legacy
Lakukan refaktor secara bertahap: temukan penggunaan getInstance(), definisikan interface, dan ubah konsumen satu per satu untuk menerima dependensi melalui konstruktor. Setelah semua konsumen ter-refaktor, Anda dapat mengelola instance di composition root atau biarkan DI container yang menangani lifecycle.
Langkah singkat:
- Identifikasi panggilan getInstance() dan batas tanggung jawabnya.
- Definisikan interface yang mencakup metode publik yang diperlukan.
- Ubah konstruktor konsumen agar menerima interface.
- Di composition root, buat dan injeksikan satu instance atau gunakan DI container.
Rangkuman Penting
- Gunakan Singleton hanya untuk layanan yang benar-benar unik.
- Prefer dependency injection untuk decoupling dan kemampuan pengujian.
- Jika menggunakan Singleton, buat lazy dan perhatikan isu konkurensi.
- Untuk sistem legacy, migrasi bertahap ke DI adalah pendekatan paling aman.
FAQ — Tanya Jawab Singkat
Kapan saya harus memakai Singleton?
Jika sebuah sumber daya benar-benar unik dan tidak berstate—misalnya logger pusat atau adapter perangkat keras—Singleton bisa masuk akal. Namun, pertimbangkan DI untuk fleksibilitas.
Bagaimana cara mengetes kode yang sudah menggunakan Singleton?
Perkenalkan interface untuk Singleton, refaktor konsumen agar menerima interface melalui konstruktor, lalu injeksikan test double saat pengujian.
Apa langkah paling aman untuk menghapus Singleton dari aplikasi lama?
Peta penggunaan, definisikan interface, refaktor konsumen satu per satu untuk menerima dependensi, lalu buat dan injeksikan satu instance di composition root atau gunakan DI container.
AI menulis kode.Anda membuatnya bertahan.
Di era akselerasi AI, kode bersih bukan hanya praktik yang baik — ini adalah perbedaan antara sistem yang berkembang dan codebase yang runtuh di bawah beratnya sendiri.