What is the best and most convenient way to implement a Singleton pattern for a class in TypeScript? (Both with and without lazy initialisation).
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();
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;
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.
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/
Not a pure singleton (initialization may be not lazy), but similar pattern with help of namespace
s.
namespace MyClass
{
class _MyClass
{
...
}
export const instance: _MyClass = new _MyClass();
}
Access to object of Singleton:
MyClass.instance
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
.