It turns out it's actually possible to apply singleton pattern using decorators in typescript.
Since decorator is essentially a wrapper-function, we can use it to return a fake anonymous class and use its constructor
to trap an instance of the decorated class in a closure variable, which we can reuse later when somebody tries to invoke
the class constructor again:
function Singleton<T extends new (...args: any[]) => any>(ctr: T): T {
let instance: T;
return class {
constructor(...args: any[]) {
if (instance) {
console.error('You cannot instantiate a singleton twice!');
return instance;
}
instance = new ctr(...args);
return instance;
}
} as T
}
Now we can use it to decorate any class to make it a singleton:
@Singleton
class User {
constructor(private name: string) { }
public sayName(): void {
console.log(`My name is ${this.name}`);
}
}
let user = new User("Bob");
let secondUser = new User("not Bob");
user.sayName(); // "Bob"
secondUser.sayName(); // still "Bob"
Interesting, eh?