I wanted to move to TypeScript from traditional JS because I like the C#-like syntax. My problem is that I can\'t find out how to declare static classes in TypeScript.
I was searching for something similar and came accross something called the Singleton Pattern
.
Reference: Singleton Pattern
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() );
TypeScript is not C#, so you shouldn't expect the same concepts of C# in TypeScript necessarily. The question is why do you want static classes?
In C# a static class is simply a class that cannot be subclassed and must contain only static methods. C# does not allow one to define functions outside of classes. In TypeScript this is possible, however.
If you're looking for a way to put your functions/methods in a namespace (i.e. not global), you could consider using TypeScript's modules, e.g.
module M {
var s = "hello";
export function f() {
return s;
}
}
So that you can access M.f() externally, but not s, and you cannot extend the module.
See the TypeScript specification for more details.
With ES6 external modules this can be achieved like so:
// privately scoped array
let arr = [];
export let ArrayModule = {
add: x => arr.push(x),
print: () => console.log(arr),
}
This prevents the use of internal modules and namespaces which is considered bad practice by TSLint [1] [2], allows private and public scoping and prevents the initialisation of unwanted class objects.
I got the same use case today(31/07/2018) and found this to be a workaround. It is based on my research and it worked for me. Expectation - To achieve the following in TypeScript:
var myStaticClass = {
property: 10,
method: function(){}
}
I did this:
//MyStaticMembers.ts
namespace MyStaticMembers {
class MyStaticClass {
static property: number = 10;
static myMethod() {...}
}
export function Property(): number {
return MyStaticClass.property;
}
export function Method(): void {
return MyStaticClass.myMethod();
}
}
Hence we shall consume it as below:
//app.ts
/// <reference path="MyStaticMembers.ts" />
console.log(MyStaticMembers.Property);
MyStaticMembers.Method();
This worked for me. If anyone has other better suggestions please let us all hear it !!! Thanks...
Defining static properties and methods of a class is described in 8.2.1 of the Typescript Language Specification:
class Point {
constructor(public x: number, public y: number) { }
public distance(p: Point) {
var dx = this.x - p.x;
var dy = this.y - p.y;
return Math.sqrt(dx * dx + dy * dy);
}
static origin = new Point(0, 0);
static distance(p1: Point, p2: Point) {
return p1.distance(p2);
}
}
where Point.distance()
is a static (or "class") method.
This is one way:
class SomeClass {
private static myStaticVariable = "whatever";
private static __static_ctor = (() => { /* do static constructor stuff :) */ })();
}
__static_ctor
here is an immediately invoked function expression. Typescript will output code to call it at the end of the generated class.
Update: For generic types in static constructors, which are no longer allowed to be referenced by static members, you will need an extra step now:
class SomeClass<T> {
static myStaticVariable = "whatever";
private ___static_ctor = (() => { var someClass:SomeClass<T> ; /* do static constructor stuff :) */ })();
private static __static_ctor = SomeClass.prototype.___static_ctor();
}
In any case, of course, you could just call the generic type static constructor after the class, such as:
class SomeClass<T> {
static myStaticVariable = "whatever";
private __static_ctor = (() => { var example: SomeClass<T>; /* do static constructor stuff :) */ })();
}
SomeClass.prototype.__static_ctor();
Just remember to NEVER use this
in __static_ctor
above (obviously).