TypeScript Singleton Pattern
Posted by robert | Filed under TypeScript
I am working on a BulkLoader class to load different types of files and wanted to use the Singleton pattern for it. This way I can load files from my main application class and retrieve the loaded files easily from other classes.
Below is a simple example how you can make a score manager for a game with TypeScript and the Singleton pattern.
class SingletonClass { private static _instance:SingletonClass = new SingletonClass(); private _score:number = 0; constructor() { if(SingletonClass._instance){ throw new Error("Error: Instantiation failed: Use SingletonDemo.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; } }
Then anywhere in your other classes you would get access to the Singleton by:
var scoreManager = SingletonClass.getInstance(); scoreManager.setScore(10); scoreManager.addPoints(1); scoreManager.removePoints(2); console.log( scoreManager.getScore() );
Example Code
You can download the files from https://github.com/codeBelt/Example-TypeScript-Singleton-Pattern. Click the “Download Zip” button.
Please leave a comment if you find this TypeScript tutorial useful.
June 5, 2013 at 12:34 am
works well.. thanks
August 10, 2013 at 5:12 pm
But if I will use the new keyword I will get another instance. no?
August 13, 2013 at 4:29 pm
Yes, you are correct. I updated the code above to enforce the Singleton pattern now. Thanks for calling that out.
September 3, 2013 at 7:11 am
Typescript lets you make the constructor private. This would be my preferred method for enforcing the singleton pattern. Attempting to use the new keyword with a private constructor will cause a compile error rather than a runtime exception (as with the current solution).
September 3, 2013 at 4:58 pm
I didn’t know you could set the constructor to private but it doesn’t look like it enforces the Singleton pattern.
I tried it and I did not get a compile error. I don’t think that is a good approach to enforce the singleton pattern. With your approach I can do the below and there is no compile error. Also they are two different objects. I am using TypeScript 0.9.1.1.
var sing1:SingletonClass = new SingletonClass();
var sing2:SingletonClass = new SingletonClass();
console.log(sing1 === sing2);
// false
September 4, 2013 at 4:25 am
Yeah it looks like I was incorrect, it doesn’t seem to correctly make the constructor private.
I tested before posting and it caused the compile error (or seemed to) but have tested again it it doesn’t. I updated to 0.9.1.1 yesterday so it’s possible I tested on 0.9.1 and it was working under that version.
January 5, 2014 at 9:16 pm
Why don’t you put
constructor() {
if(SingletonClass._instance){
return SingletonClass._instance;
}
SingletonClass._instance = this;
}
January 7, 2014 at 5:43 pm
Not sure. That’s how I’ve always seen it. Your way works but it could be confusing to another developer. It does not enforce the getInstance(); usage and I would say it does not follow the Singleton pattern.
Someone could use your Singleton class like below and assume they have created two different instances. Which they have not, they are both the same object.
var one = new SingletonClass();
var two = new SingletonClass();
// (one===two) does equal true as the same object.
var three = SingletonClass.getInstance();
// three is the same object as one and two.
With coding I find limiting the number of ways you can do something better. Or your documentation will look: “You can do it this way, or this way or this way to accomplish the same task.”
June 10, 2014 at 5:56 pm
Thanks for this terrific example. Very helpful.
June 11, 2014 at 7:35 am
In my opinion the best way to do a singleton is this:
class Singleton {
/**
* The Singleton Instance
*/
private static _instance:Singleton;
/**
* constructor throws error if this property is false,
* only the getInstance() method could set it to true
*/
private static allowInstance:boolean = false;
/**
* The constructor should not be used, use getInstance() instead
*/
constructor(){
if(!Ready.allowInstance){
throw new Error("Error: Instantiation failed: Use Singleton.getInstance() instead of new.");
}
}
/**
* Returns the instance of Singleton
*
* @returns object {Singleton}
*/
public static getInstance():Singleton {
if(Singleton._instance === null) {
Singleton.allowInstance = true;
Singleton._instance = new Singleton();
Singleton.allowInstance = false;
}
return Singleton._instance;
}
}
June 27, 2014 at 9:37 pm
I still like my way. Thanks for sharing.
June 26, 2014 at 11:42 am
Hi
sorry but for me don’t works :(
I try to “new SingletonClass()” and I never seen a log or error that alert me…
It’s very courius… Thank you!
June 27, 2014 at 9:32 pm
Are you sure. Did you check the console area on your browser? I get “Uncaught Error: Error: Instantiation failed: Use SingletonDemo.getInstance() instead of new.”
April 29, 2015 at 7:17 pm
Here’s the problem: If you immediately call “new SingletonClass()” it will not throw an exception because “if(SingletonClass._instance)” will return false.
If you call getInstance() first, then trying to call “new SingletonClass()” will fail as desired. But you can’t guarantee what somebody will try to do.
Bastian’s answer handles it, but the extra variable is unfortunate.
Another hacky but workable option is to have the instance method set the variable to undefined instead of null. Then the constructor only works if the instance variable is undefined rather than the default (null). I don’t like it, but it’s the best workaround I can think of.
The real solution is for TypeScript to allow private constructors.
April 29, 2015 at 9:44 pm
I think maybe the solution is to assign the _instance property right away like below. I also update the example above.
private static _instance:SingletonClass = new SingletonClass();
Then we can just return the instance:
public static getInstance():SingletonClass {
return SingletonClass._instance;
}
May 24, 2016 at 12:25 pm
Here is my solution to the singleton pattern in TypeScript enforcing private constructor:
export abstract class SingletonFactory {
private static _instance: SingletonFactory;
public static getInstance(): SingletonFactory {
if (SingletonFactory._instance == null) {
SingletonFactory._instance = new SingletonFactoryImpl();
}
return SingletonFactory._instance;
}
public somethingUsefull() { ... }
}
class SingletonFactoryImpl extends SingletonFactory { }
Now I can call SingletonFactory.getInstance() and receive an instance, but I also cannot run new SingletonFactory because it is an abstract class. Since the implementation isn’t exported, no one can get to it but the factory.
Although, I have to call out that this pattern would be better with the logic of the factory (somethingUseful()) actually being defined in the Impl class and only the interface being defined in the Factory class itself. It gets the point across.
-Brenton