Wzorzec Singleton zapewnia jedną instancję klasy i pojedynczy punkt dostępu do współdzielonego zasobu. Ten przewodnik pokaże, kiedy użyć Singletona, jak go bezpiecznie zaimplementować w TypeScript oraz jakie alternatywy — np. wstrzykiwanie zależności i kontenery IoC — warto rozważyć.
January 19, 2026 (7mo ago) — last updated May 29, 2026 (3mo ago)
Singleton w TypeScript: kompletny przewodnik
Naucz się wzorca Singleton: zastosowania, implementacja w TypeScript, wpływ na testowalność i bezpieczne alternatywy jak DI i kontenery IoC.
← Back to blog
Opanowanie wzorca Singleton w TypeScript: Kompletny przewodnik

W świecie tworzenia oprogramowania niektóre narzędzia są potężne, ale wymagają ostrożnego stosowania. Wzorzec Singleton zapewnia, że dana klasa ma tylko jedną instancję i udostępnia pojedynczy, globalny punkt dostępu do niej. Zrozumienie, kiedy go użyć, jak go bezpiecznie zaimplementować w TypeScript i jakie istnieją alternatywy, pomoże ci podejmować lepsze decyzje projektowe1.
Czym jest wzorzec Singleton i kiedy jest użyteczny?
Wyobraź sobie średniowieczne królestwo z tylko jednym oficjalnym Królewskim Pisarzem. Ta osoba jest jedyną upoważnioną do zapisywania dekretów, dzięki czemu rejestry są spójne. Wzorzec Singleton działa podobnie w oprogramowaniu: ogranicza klasę tak, by mogła istnieć tylko jedna instancja, która staje się źródłem prawdy dla określonego zadania.
Główne zalety to centralizacja kontroli nad zasobami, ograniczenie duplikacji i oszczędność pamięci. Przykłady zastosowań obejmują menedżery konfiguracji, loggery czy puli połączeń do bazy danych. Jednak decyzja o użyciu Singletona wymaga rozważenia wpływu na testowalność i utrzymywalność kodu.
Główne przeznaczenie i analogia
Singleton to nie tylko sposób na blokadę tworzenia obiektów; to centralizacja odpowiedzialności. Tak jak Królewski Pisarz zapewnia jeden punkt dostępu do oficjalnych rejestrów, instancja Singleton oferuje uniwersalny dostęp do współdzielonego zasobu.
Klasycznym przykładem jest pula połączeń do bazy danych — nie chcesz, by każdy komponent otwierał osobne połączenie. Zamiast tego jedna instancja może zarządzać pulą i wydzielać połączenia efektywnie.
Jedna klasa, jedna instancja, jeden punkt dostępu — prosta idea z dalekosiężnymi konsekwencjami.
Najważniejsze cechy wzorca
| Cecha | Co to oznacza |
|---|---|
| Pojedyncza instancja | Klasa zaprojektowana tak, by mieć tylko jedną instancję, często przez prywatny konstruktor. |
| Globalny punkt dostępu | Statyczna metoda (np. getInstance()) daje jednolity sposób dostępu do instancji. |
| Opóźniona inicjalizacja | Instancja tworzona przy pierwszym żądaniu, co może zmniejszyć koszty startu. |
| Zarządzanie stanem | Centralne miejsce dla fragmentu globalnego stanu, np. ustawień aplikacji. |
Praktyczne przypadki użycia
Najlepiej stosować Singletony tam, gdzie zasób jest z natury unikalny:
- Usługi logowania: jeden logger zapewnia spójność logów.
- Zarządzanie konfiguracją: jedno źródło ustawień aplikacji.
- Interfejs do sprzętu: pojedynczy adapter do urządzenia zapobiega konfliktom.
Zalety i wady

Zalety
- Globalny punkt dostępu upraszcza użycie w różnych modułach.
- Opóźniona inicjalizacja oszczędza zasoby przy starcie.
- Redukcja duplikacji zapobiega konfliktom między instancjami.
Wady
- Ścisłe powiązanie ukrywa zależności i utrudnia testowanie.
- Współdzielony mutowalny stan może prowadzić do trudnych do znalezienia błędów.
- Ukryte skutki uboczne: metody nie ujawniają zależności w sygnaturze.
Wpływ na testowanie i powiązania
Singletony komplikują testy jednostkowe przez trwały, globalny stan. Mockowanie takiego obiektu może być niewygodne, dlatego nowoczesne zespoły często wybierają wstrzykiwanie zależności (DI), które czyni zależności jawymi i łatwymi do zastąpienia podczas testów3.
Równoważenie kompromisów
Rozważ wygodę kontra utrzymywalność. W projektach legacy najbezpieczniejsza jest stopniowa refaktoryzacja w kierunku DI: zachowujesz dotychczasowe zachowanie, jednocześnie redukując ukryte powiązania.
Implementacja Singletona w TypeScript

Poniżej praktyczny, typowany przykład Singletona w TypeScript. Sekret to prywatny konstruktor i statyczna metoda strażniczka.
Przykład: ConfigManager
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);
}
}
// const config = new ConfigManager(); // Błąd: konstruktor jest prywatny
Wykorzystanie w serwisie
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}...`);
// Logika pobierania danych
}
}
console.log("Application starting...");
const service1 = new ApiService();
service1.fetchData();
const service2 = new ApiService();
console.log("Application finished.");
Po uruchomieniu zobaczysz inicjalizację ConfigManagera tylko raz, co potwierdza działanie Singletona.
Dlaczego Singletony mają złą reputację
Singletony są atrakcyjne przez prostotę, ale często prowadzą do ukrytych zależności, globalnego mutowalnego stanu i problemów z testowaniem. Kiedy klasa cicho sięga po instancję globalną, ukrywa zależność, która powinna być jawna w konstruktorze, co utrudnia zrozumienie i testowanie kodu3.
Problemy ze współbieżnością
Stanowe Singletony mogą prowadzić do warunków wyścigu; rozważ licznik sesji, gdzie dwa jednoczesne żądania inkrementują ten sam licznik bez synchronizacji — takie błędy są zależne od czasu i trudne do odtworzenia7.
Testowanie
Globalny stan może wyciekać między testami, a mockowanie Singletona bywa nieporęczne. DI upraszcza testy, bo mocki można wstrzykiwać bezpośrednio.
Nowoczesne alternatywy
Zamiast programowego Singletona, rozważ wstrzykiwanie zależności i kontenery IoC. DI czyni zależności jawymi i poprawia testowalność oraz modułowość.
DI kontra Singleton
Przykład: zamiast pobierać Singleton w konstruktorze, przyjmij menedżera konfiguracji przez konstruktor.
interface IConfigManager { get(key: string): any; }
class ApiService {
private apiUrl: string;
constructor(config: IConfigManager) {
this.apiUrl = config.get("API_URL");
}
}
Teraz ApiService zależy od kontraktu, co pozwala w testach przekazać fikcyjny obiekt.
Kontenery IoC
Frameworki takie jak NestJS czy biblioteki jak InversifyJS zarządzają tworzeniem i cyklem życia obiektów, pozwalając uzyskać zachowanie podobne do Singletona bez ukrytych powiązań45.
Refaktoryzacja Singletonów w kodzie legacy
Postępuj inkrementalnie: zidentyfikuj wywołania getInstance(), zdefiniuj interfejs, refaktoryzuj konsumentów na DI i w punkcie kompozycji przekaż jedną instancję lub pozwól kontenerowi DI zarządzać cyklem życia.
Kroki
- Zidentyfikuj i zlokalizuj wszystkie wywołania Singletona.
- Zdefiniuj interfejs publicznych metod implementacji.
- Refaktoryzuj konsumentów, aby akceptowali interfejs przez konstruktor.
- Utwórz instancję w punkcie kompozycji lub użyj kontenera DI.
FAQ — Szybkie pytania i odpowiedzi
P: Kiedy Singleton jest właściwy? A: Gdy zasób jest naprawdę unikalny i bezstanowy, np. centralny logger lub adapter do sprzętu. Preferuj DI, gdy to możliwe.
P: Jak testować kod używający Singletona? A: Wprowadź interfejs, refaktoryzuj konsumentów, aby akceptowali zależność i wstrzykuj stuby/mocki. Migrację wykonuj stopniowo.
P: Czy klasa statyczna to to samo co Singleton? A: Nie. Klasa statyczna ma tylko statyczne członkowskie elementy. Singleton to jedna instancja, którą można przekazywać jako obiekt i implementować interfejsy.
Q&A — Krótkie odpowiedzi na najczęstsze wątpliwości
Czy Singleton zawsze szkodzi? Nie. Ma sens dla naprawdę unikalnych zasobów, ale zwykle DI oferuje większą elastyczność i lepszą testowalność.
Jak ograniczyć ryzyko podczas używania Singletona? Używaj leniwej inicjalizacji, dbaj o bezpieczeństwo współbieżne i udokumentuj punkt kompozycji, skąd instancja jest udostępniana.
Jak zacząć refaktoryzację w dużym projekcie? Zmapuj użycia Singletonów, wprowadź interfejsy i refaktoryzuj pojedynczych konsumentów na DI, utrzymując kompatybilność przez punkty kompozycji.
Dalsze lektury i zasoby
Zobacz także: Wzorce projektowe, Wstrzykiwanie zależności oraz oficjalny podręcznik TypeScript: TypeScript Handbook.
AI pisze kod.Ty sprawiasz, że przetrwa.
W erze przyspieszenia AI czysty kod to nie tylko dobra praktyka — to różnica między systemami, które się skalują, a bazami kodu, które zapadają się pod własnym ciężarem.