3

I'm a beginner in typescript and I have read a lot about typescript & singletons, and I still can get it work.

I have the same problem as this: Node.js & Typescript Singleton pattern : seems like singleton is not shared between singleton users.

I have read this article too: https://fullstack-developer.academy/singleton-pattern-in-typescript/ and this one: http://www.codebelt.com/typescript/typescript-singleton-pattern/

In the end, when i go from a module to another, its seems like my singleton class is always at is default state.

When calling getInstance(), since the value is set to new Path(), it seems obvious to me that the singleton is always at is default state, but in many sources online (like the previous two provided) it is the way to do it.

What am I doing wrong ? Thanks.

Here is my singleton (Path.ts):

class Path{
    private static _instance: Path = new Path();
    private _nodes: NodeModel[];
    private _links: LinkModel[];

    public static getInstance(): Path{
        if(Path._instance)
            return Path._instance;
        else
            throw new Error("Path is not initialized.");
    }

    public setPath(nodes: NodeModel[], links: LinkModel[]){
        this._nodes = nodes;
        this._links = links;
    }

    public nodes(){ return this._nodes; }
  [...]
}
export = Path;

PathDefinition.ts

module PathDefinition{
    export function defaultDefinition(){
        var nodes = [
            new NodeModel(...),
            new NodeModel(...)
        ];
        var links = [
            new LinkModel(...),
            new LinkModel(...)
        ];
        Path.getInstance().setPath(nodes, links);
    }
}
export = PathDefinition;

controller.ts

module Controller{
    export function init(){
        console.log(Airflow.getInstance().nodes());
        //console.log => undefined
    }
}

EDIT

As a C# developer, I thought that wrapping each file content into a "module" (or namespace as mentioned by Paleo) was the best way to organize my code. After reading provided links by Paleo and especially this one : How do I use namespaces with TypeScript external modules? , I understand why my above code is not the best way to do with Typescript.

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
mp9007
  • 79
  • 2
  • 11
  • It should work. But… What a terrible code! You use `module` to create a `namespace`. The legacy `export =` seems to be the only way. And you make a unique instance (ie. a singleton) of a class (which is made to create multiple instances) in a module (which is a singleton). The principle of singleton is a nonsense in JavaScript. You want a single object? Just create a single object. – Paleo Apr 27 '18 at 13:38
  • @Paleo I know my code isnt perfect yet. Not very nice to say it's terrible. I did a class singleton the "c#" way. Because I have properties in it and method that affect those properties. So, I thought that a module/namespace whatever was not the proper type. Can you just explain more the `module` vs `namespace` thing? And your sentence about the `export =`, i just don't get it. – mp9007 Apr 27 '18 at 14:16
  • Regarding the way we should use `export`, I suggest an [introduction to ES6 modules](https://hacks.mozilla.org/2015/08/es6-in-depth-modules/). Then, read the section on `export =` [in the TypeScript documentation](https://www.typescriptlang.org/docs/handbook/modules.html). `export =` is not part of the standard, it is the old CommonJS/AMD way in TypeScript. – Paleo Apr 28 '18 at 16:26
  • Regarding the keyword `module` as you use it, it has been replaced by `namespace` in order to align to the standard (see [the first note here](https://www.typescriptlang.org/docs/handbook/namespaces.html)). Namespaces is a TypeScript way to use the old IIFE pattern. See also: https://stackoverflow.com/questions/44493381/namespaces-vs-modules-vs-typings-in-typescript – Paleo Apr 28 '18 at 16:36
  • 1
    @Paleo Thanks for the precision and for the links. I'll read this right away ! – mp9007 Apr 30 '18 at 12:24

1 Answers1

7

Here is a cut down example that results in re-using the same instance of your Path class. I have removed most code to just show things working.

module.ts

class Path {
    public nodes: string[] = [];
}

export const PathSingleton = new Path();

The const here is only going to exist once, even though we're going to import this module in a few places...

othermodule.ts

import { PathSingleton } from './module';

PathSingleton.nodes.push('New OtherModule Node');
console.log(PathSingleton.nodes);

export const example = 1;

We have added to the node list in this module...

app.ts

import { PathSingleton } from './module';
import { example } from './othermodule';

PathSingleton.nodes.push('New Node');
console.log(PathSingleton.nodes);

const x = example;

We are also adding to it here.

Running this simple app results in the following output...

From othermodule.js
[ 'New OtherModule Node' ]
From app.js
[ 'New OtherModule Node', 'New Node' ]

That last line is the "proof" that all the interactions are occurring against the same instance.

denov
  • 11,180
  • 2
  • 27
  • 43
Fenton
  • 241,084
  • 71
  • 387
  • 401