What is the best and most convenient way to implement a Singleton pattern for a class in TypeScript? (Both with and without lazy initialisation).
25 Answers
Since TS 2.0, we have the ability to define visibility modifiers on constructors, so now we can do singletons in TypeScript just like we are used to from other languages.
Example given:
class MyClass
{
private static _instance: MyClass;
private constructor()
{
//...
}
public static get Instance()
{
// Do you need arguments? Make it a regular static method instead.
return this._instance || (this._instance = new this());
}
}
const myClassInstance = MyClass.Instance;
Thank you @Drenai for pointing out that if you write code using the raw compiled javascript you will not have protection against multiple instantiation, as the constraints of TS disappears and the constructor won't be hidden.
18 Comments
Singleton classes in TypeScript are generally an anti-pattern. You can simply use namespaces instead.
Useless singleton pattern
class Singleton {
/* ... lots of singleton logic ... */
public someMethod() { ... }
}
// Using
var x = Singleton.getInstance();
x.someMethod();
Namespace equivalent
export namespace Singleton {
export function someMethod() { ... }
}
// Usage
import { SingletonInstance } from "path/to/Singleton";
SingletonInstance.someMethod();
var x = SingletonInstance; // If you need to alias it for some reason
15 Comments
export default new Singleton()?The best way I have found is:
class SingletonClass {
private static _instance:SingletonClass = new SingletonClass();
private _score:number = 0;
constructor() {
if(SingletonClass._instance){
throw new Error("Error: Instantiation failed: Use SingletonClass.getInstance() instead of new.");
}
SingletonClass._instance = this;
}
public static getInstance():SingletonClass
{
return SingletonClass._instance;
}
public setScore(value:number):void
{
this._score = value;
}
public getScore():number
{
return this._score;
}
public addPoints(value:number):void
{
this._score += value;
}
public removePoints(value:number):void
{
this._score -= value;
}
}
Here is how you use it:
var scoreManager = SingletonClass.getInstance();
scoreManager.setScore(10);
scoreManager.addPoints(1);
scoreManager.removePoints(2);
console.log( scoreManager.getScore() );
https://codebelt.github.io/blog/typescript/typescript-singleton-pattern/
5 Comments
The following approach creates a Singleton class that can be used exacly like a conventional class:
class Singleton {
private static instance: Singleton;
//Assign "new Singleton()" here to avoid lazy initialisation
constructor() {
if (Singleton.instance) {
return Singleton.instance;
}
this. member = 0;
Singleton.instance = this;
}
member: number;
}
Each new Singleton() operation will return the same instance. This can however be unexpected by the user.
The following example is more transparent to the user but requires a different usage:
class Singleton {
private static instance: Singleton;
//Assign "new Singleton()" here to avoid lazy initialisation
constructor() {
if (Singleton.instance) {
throw new Error("Error - use Singleton.getInstance()");
}
this.member = 0;
}
static getInstance(): Singleton {
Singleton.instance = Singleton.instance || new Singleton();
return Singleton.instance;
}
member: number;
}
Usage: var obj = Singleton.getInstance();
5 Comments
new Class(...) syntax.I am surprised not to see the following pattern here, which actually looks very simple.
// shout.ts
class ShoutSingleton {
helloWorld() { return 'hi'; }
}
export let Shout = new ShoutSingleton();
Usage
import { Shout } from './shout';
Shout.helloWorld();
10 Comments
Shout class thoughexport let Shout = new ShoutSingleton(); is that it's not the Singleton pattern because it doesn't fulfill the Singleton's objective of 'Ensuring that a class has only one instance.' This is because every time you import it, you create new instances instead of reusing the same one. In short, for it to be a Singleton, you would need to ensure that the same instance is always returned, not a new one. This is resolved by adding 'Lazy Initialization.'Add the following 6 lines to any class to make it "Singleton".
class MySingleton
{
private constructor(){ /* ... */}
private static _instance: MySingleton;
public static getInstance(): MySingleton
{
return this._instance || (this._instance = new this());
};
}
var test = MySingleton.getInstance(); // will create the first instance
var test2 = MySingleton.getInstance(); // will return the first instance
alert(test === test2); // true
[Edit]: Use Alex answer if you prefer to get the instance through a property rather a method.
[Edit 2]: Bonus: if you want to generate a singleton from your existing class in one line, you can use this class builder:
function AsSingleton<T extends new (...args: any[]) => any>(Aclass: T, ...args: ConstructorParameters<T>) {
return class extends Aclass {
static #instance: InstanceType<T>;
public static getInstance(): InstanceType<T> {
if (!this.#instance) {
this.#instance = new Aclass(...args);
}
return this.#instance;
}
} as Omit<T,"new"> & {getInstance:()=>InstanceType<T>};
}
Check this snippet for an example (even more advanced)
usage: const AClassSingleton = AsSingleton(AClass);
5 Comments
new MySingleton() , say 5 times? does your code reserve a single instance?2025 Update
Static Factory/Construtor Only Pattern (SFOP)
The purpose of this pattern is to restrict the creation of instances of a class exclusively through static factory methods, preventing direct use of the class constructor. This is useful to ensure that all instances are created with specific configurations or defined validations, allowing easy creation of singletons, object pools, asynchronous constructors, and more.
In Javascript/TypeScript, this can be implemented with the following steps:
StaticConstructorOnlyPattern.new(constructor, ...args): Method that adds a symbolic key to the target class, indicating that the next constructor call is allowed. It then creates and returns a new instance of the class with the provided arguments.StaticConstructorOnlyPattern.throw(constructor): Method that checks whether the symbolic key is defined. If it is not, it throws an error indicating that the constructor should not be called directly; however, if the key is present, it removes the key to avoid improper reuse and allows the constructor to proceed with instance creation.
// PatterStaticFactory.ts
const comparekey = Symbol()
function $throw(Self: Function) {
if ((Self as any)[comparekey])
return void Reflect.set(Self, comparekey, false)
const constructor = Self.prototype.constructor.name
throw `new ${constructor}() is not allowed. Use ${constructor}.new() instead.`
}
function $new<A extends any[] = []>(Self: Function, ...args: A) {
Reflect.set(Self, comparekey, true)
return new (Self as any)(...args)
}
export const StaticConstructorOnlyPattern = {
throw: $throw,
new: $new
}
In the example below, the SfopClass uses the Static Factory Only Pattern. This ensures that instances can only be created through the static method SfopClass.new(...), and any attempt to use the constructor directly with new SfopClass(...) will result in an error. This is done by following these steps:
StaticConstructorOnlyPattern.throw(constructor)is executed in the target class constructor to check whether the instance has permission to be created. This permission is granted only when the static methodStaticConstructorOnlyPattern.new(...)is called.- If the permission is not present, an error is thrown, preventing direct instance creation.
- If the permission is present, the method
StaticConstructorOnlyPattern.throw(...)removes the symbolic key to avoid improper reuse and allows the constructor to proceed with instance creation.
StaticConstructorOnlyPattern.new<CtorArgs>(this, ...args)adds the required permission and then creates the class instance.
- This process works because constructors cannot be asynchronous. Thus, only the method
StaticConstructorOnlyPattern.new(...)can assign the permission before the constructor call, andStaticConstructorOnlyPattern.throw(...)can check this permission, allowing or denying instance creation and removing the permission immediately afterward to avoid improper reuse.
// main.ts
import { StaticConstructorOnlyPattern as sfop } from "./PatterStaticFactory"
type CtorArgs =
| [a: number, b: string]
| [a: string, b: number]
| [a: boolean, b: boolean]
class SfopClass {
protected constructor(...args: CtorArgs) {
sfop.throw(new.target)
console.log("Z constructor")
}
static new(...args: CtorArgs) {
return sfop.new<CtorArgs>(this, ...args)
}
}
// Factory Calls
SfopClass.new('str', 1)
SfopClass.new(1, 'str')
SfopClass.new(true, true)
Example of how to use the SFOP pattern to create a Singleton class:
// singleton.ts
import { StaticConstructorOnlyPattern as sfop } from "./StaticConstructorOnly"
class Singleton {
static #instance: Singleton | undefined
protected constructor() {
sfop.throw(new.target)
}
static createInstance() {
return this.#instance ??= sfop.new(this)
}
}
// Usage
const obj1 = Singleton.createInstance()
const obj2 = Singleton.createInstance()
console.log(obj1 === obj2) // true
2021 update
Now constructor can be private
export default class Singleton {
private static _instance?: Singleton;
private constructor() {
if (Singleton._instance)
throw new Error("Use Singleton.instance instead of new.");
Singleton._instance = this;
}
static get instance() {
return Singleton._instance ?? (Singleton._instance = new Singleton());
}
}
My early solution:
export default class Singleton {
private static _instance: Singleton = new Singleton();
constructor() {
if (Singleton._instance)
throw new Error("Use Singleton.instance");
Singleton._instance = this;
}
static get instance() {
return Singleton._instance;
}
}
1 Comment
return Modal._instance. This way, if you new that class, you get the existing object, not a new one.You can use class expressions for this (as of 1.6 I believe).
var x = new (class {
/* ... lots of singleton logic ... */
public someMethod() { ... }
})();
or with the name if your class needs to access its type internally
var x = new (class Singleton {
/* ... lots of singleton logic ... */
public someMethod(): Singleton { ... }
})();
Another option is to use a local class inside of your singleton using some static members
class Singleton {
private static _instance;
public static get instance() {
class InternalSingleton {
someMethod() { }
//more singleton logic
}
if(!Singleton._instance) {
Singleton._instance = new InternalSingleton();
}
return <InternalSingleton>Singleton._instance;
}
}
var x = Singleton.instance;
x.someMethod();
Comments
i think maybe use generics be batter
class Singleton<T>{
public static Instance<T>(c: {new(): T; }) : T{
if (this._instance == null){
this._instance = new c();
}
return this._instance;
}
private static _instance = null;
}
how to use
step1
class MapManager extends Singleton<MapManager>{
//do something
public init():void{ //do }
}
step2
MapManager.Instance(MapManager).init();
1 Comment
static Instance method and the type of _instance, then use like MapManager.Instance(MapManager) as MapManager. This could eliminate the type mismatch error of eslint.You can also make use of the function Object.Freeze(). Its simple and easy:
class Singleton {
instance: any = null;
data: any = {} // store data in here
constructor() {
if (!this.instance) {
this.instance = this;
}
return this.instance
}
}
const singleton: Singleton = new Singleton();
Object.freeze(singleton);
export default singleton;
5 Comments
if (!this.instance) in the constructor? Is that just an extra precaution in case you created multiple instances before the export?I have found a new version of this that the Typescript compiler is totally okay with, and I think is better because it doesn't require calling a getInstance() method constantly.
import express, { Application } from 'express';
export class Singleton {
// Define your props here
private _express: Application = express();
private static _instance: Singleton;
constructor() {
if (Singleton._instance) {
return Singleton._instance;
}
// You don't have an instance, so continue
// Remember, to set the _instance property
Singleton._instance = this;
}
}
This does come with a different drawback. If your Singleton does have any properties, then the Typescript compiler will throw a fit unless you initialize them with a value. That's why I included an _express property in my example class because unless you initialize it with a value, even if you assign it later in the constructor, Typescript will think it hasn't been defined. This could be fixed by disabling strict mode, but I prefer not to if possible. There is also another downside to this method I should point out, because the constructor is actually getting called, each time it does another instance is technically created, but not accessible. This could, in theory, cause memory leaks.
Comments
After implementing a classic pattern like
class Singleton {
private instance: Singleton;
private constructor() {}
public getInstance() {
if (!this.instance) {
this.instance = new Singleton();
}
return this.instance;
}
}
I realized it's pretty useless in case you want some other class to be a singleton too. It's not extendable. You have to write that singleton stuff for every class you want to be a singleton.
Decorators for the rescue.
@singleton
class MyClassThatIsSingletonToo {}
You can write decorator by yourself or take some from npm. I found this proxy-based implementation from @keenondrums/singleton package neat enough.
Comments
/**
* The Singleton class defines the `getInstance` method that lets clients access
* the unique singleton instance.
*/
class Singleton {
private static instance: Singleton;
/**
* The Singleton's constructor should always be private to prevent direct
* construction calls with the `new` operator.
*/
private constructor() { }
/**
* The static method that controls the access to the singleton instance.
*
* This implementation let you subclass the Singleton class while keeping
* just one instance of each subclass around.
*/
public static getInstance(): Singleton {
if (!Singleton.instance) {
Singleton.instance = new Singleton();
}
return Singleton.instance;
}
/**
* Finally, any singleton should define some business logic, which can be
* executed on its instance.
*/
public someBusinessLogic() {
// ...
}
}
/**
* The client code.
*/
function clientCode() {
const s1 = Singleton.getInstance();
const s2 = Singleton.getInstance();
if (s1 === s2) {
console.log('Singleton works, both variables contain the same instance.');
} else {
console.log('Singleton failed, variables contain different instances.');
}
}
clientCode();
3 Comments
This is probably the longest process to make a singleton in typescript, but in larger applications is the one that has worked better for me.
First you need a Singleton class in, let's say, "./utils/Singleton.ts":
module utils {
export class Singleton {
private _initialized: boolean;
private _setSingleton(): void {
if (this._initialized) throw Error('Singleton is already initialized.');
this._initialized = true;
}
get setSingleton() { return this._setSingleton; }
}
}
Now imagine you need a Router singleton "./navigation/Router.ts":
/// <reference path="../utils/Singleton.ts" />
module navigation {
class RouterClass extends utils.Singleton {
// NOTICE RouterClass extends from utils.Singleton
// and that it isn't exportable.
private _init(): void {
// This method will be your "construtor" now,
// to avoid double initialization, don't forget
// the parent class setSingleton method!.
this.setSingleton();
// Initialization stuff.
}
// Expose _init method.
get init { return this.init; }
}
// THIS IS IT!! Export a new RouterClass, that no
// one can instantiate ever again!.
export var Router: RouterClass = new RouterClass();
}
Nice!, now initialize or import wherever you need:
/// <reference path="./navigation/Router.ts" />
import router = navigation.Router;
router.init();
router.init(); // Throws error!.
The nice thing about doing singletons this way is that you still use all the beauty of typescript classes, it gives you nice intellisense, the singleton logic keeps someway separated and it's easy to remove if needed.
Comments
Another option is to use Symbols in your module. This way you can protect your class, also if the final user of your API is using normal Javascript:
let _instance = Symbol();
export default class Singleton {
constructor(singletonToken) {
if (singletonToken !== _instance) {
throw new Error("Cannot instantiate directly.");
}
//Init your class
}
static get instance() {
return this[_instance] || (this[_instance] = new Singleton(_singleton))
}
public myMethod():string {
return "foo";
}
}
Usage:
var str:string = Singleton.instance.myFoo();
If the user is using your compiled API js file, also will get an error if he try to instantiate manually your class:
// PLAIN JAVASCRIPT:
var instance = new Singleton(); //Error the argument singletonToken !== _instance symbol
Comments
In Typescript, one doesn't necessarily have to follow the new instance() Singleton methodology. An imported, constructor-less static class can work equally as well.
Consider:
export class YourSingleton {
public static foo:bar;
public static initialise(_initVars:any):void {
YourSingleton.foo = _initvars.foo;
}
public static doThing():bar {
return YourSingleton.foo
}
}
You can import the class and refer to YourSingleton.doThing() in any other class. But remember, because this is a static class, it has no constructor so I usually use an intialise() method that is called from a class that imports the Singleton:
import {YourSingleton} from 'singleton.ts';
YourSingleton.initialise(params);
let _result:bar = YourSingleton.doThing();
Don't forget that in a static class, every method and variable needs to also be static so instead of this you would use the full class name YourSingleton.
Comments
After scouring this thread and playing around with all the options above - I settled with a Singleton that can be created with proper constructors:
export default class Singleton {
private static _instance: Singleton
public static get instance(): Singleton {
return Singleton._instance
}
constructor(...args: string[]) {
// Initial setup
Singleton._instance = this
}
work() { /* example */ }
}
It would require an initial setup (in main.ts, or index.ts), which can easily be implemented by
new Singleton(/* PARAMS */)
Then, anywhere in your code, just call Singleton.instnace; in this case, to get work done, I would call Singleton.instance.work()
1 Comment
Here is yet another way to do it with a more conventional javascript approach using an IFFE:
module App.Counter {
export var Instance = (() => {
var i = 0;
return {
increment: (): void => {
i++;
},
getCount: (): number => {
return i;
}
}
})();
}
module App {
export function countStuff() {
App.Counter.Instance.increment();
App.Counter.Instance.increment();
alert(App.Counter.Instance.getCount());
}
}
App.countStuff();
View a demo
2 Comments
Instance variable? You coukd simply put the variable and the functions directly under App.Counter.This is the simplest way
class YourSingletoneClass {
private static instance: YourSingletoneClass;
private constructor(public ifYouHaveAnyParams: string) {
}
static getInstance() {
if(!YourSingletoneClass.instance) {
YourSingletoneClass.instance = new YourSingletoneClass('If you have any params');
}
return YourSingletoneClass.instance;
}
}
Comments
Lets go by an example, I want to create singleton class by which I will able to create a connection of a client then I want to use that same connected client everywhere.
import nats, { Stan } from 'node-nats-streaming';
class NatsWrapper {
private _client?: Stan;
get client() {
if (!this._client) {
throw new Error('Cannot access NATS client before connecting');
}
return this._client;
}
connect(clusterId: string, clientId: string, url: string) {
this._client = nats.connect(clusterId, clientId, { url });
return new Promise((resolve, reject) => {
this.client.on('connect', (result) => {
console.log('Connected to NATS');
resolve(result);
});
this.client.on('error', (err) => {
reject(err);
});
});
}
}
// since we create and export the instace, it will act like a singleton
export const natsWrapper = new NatsWrapper();
Now, first create the conneciton in your index.ts/app.ts file then you will be able to access the same client just by importing anywhere
index.ts
await natsWrapper.connect(
'ticketing',
'client_id_random_str',
'http://nats-srv:4222'
);
someFile.ts
import { natsWrapper } from '../nats-wrapper';
const abc = () =>{
console.log(natsWrapper.client)
}
Comments
I have struggled to find a proper solution for declaring singleton pattern class in typescript.
I think below is more practical solution.
class MySingletonClass {
public now:Date = new Date();
public arg:string;
constructor(arg:string) {
this.arg = arg;
// Make singleton
if ('instance' in MySingletonClass) return Object.getOwnPropertyDescriptor(MySingletonClass, 'instance')?.value;
Object.assign(MySingletonClass, { instance: this });
}
}
const a = new MySingletonClass('a');
console.log(a);
const b = new MySingletonClass('b');
console.log(b);
console.log('a === b', a === b);
console.log('a.now === b.now', a.now === b.now);
Comments
class Singleton<CREATOR extends () => any>
{
private m_fnGetInstance: () => ReturnType<CREATOR>;
public get Instance() { return this.m_fnGetInstance(); }
public constructor(creator: CREATOR) {
this.m_fnGetInstance = () => {
const instance = creator();
this.m_fnGetInstance = () => instance;
return instance;
};
}
}
const Foo = new Singleton(() => new class {
public bar() {}
});
Foo.Instance.bar();
It is fast because there is no conditional branching.
Comments
Template One
class Singleton {
/**
* private : Making instance private ensuring that it can only be accessed with Singleton class itself.
* static : Making instance static means it belongs to class itself rather than instances of the classes. This ensures that there is only one instance of "instance" shared across all instances of the class
*/
private static instance: Singleton;
/**
* private : Making the constructor "private" prevents instantiation of the class from outside.
*/
private constructor() {}
public static getInstance(): Singleton {
if(!Singleton.instance){
Singleton.instance = new Singleton();
}
return Singleton.instance;
}
}
Template Two (Early Loading)
class DatabaseConnection{
private static instance = new DatabaseConnection();
private constructor() {};
public static getInstance(): DatabaseConnection {
return DatabaseConnection.instance;
}
}
Template Three
class DatabaseConnection{
private static instance : DatabaseConnection;
private constructor(){};
public static getInstance(): DatabaseConnection{
if(!DatabaseConnection.instance){
DatabaseConnection.instance = new DatabaseConnection();
}
return DatabaseConnection.instance;
}
}
1 Comment
namespace MySingleton {
interface IMySingleton {
doSomething(): void;
}
class MySingleton implements IMySingleton {
private usePrivate() { }
doSomething() {
this.usePrivate();
}
}
export var Instance: IMySingleton = new MySingleton();
}
This way we can apply an interface, unlike in Ryan Cavanaugh's accepted answer.