How to define a class AND constants in a CommonJS module - node.js

I have seen this thread on how to share constants across CommonJS modules:
How do you share constants in NodeJS modules?
However, if I want the same file to also have a class which should be exposed in the module, then how do I achieve that?
If I do:
module.exports = class A { ... }
Then I "used" the module.exports object.
Is there a way to mix both class AND constants in the same file?
In es6, I would simple add the term "export" before each one...

module.exports = ... is a bad practice if there's a chance that a module can have more than one exported value.
There's already existing module.exports object that is aliased as exports, it's purpose is similar to named exports in ES modules:
exports.A = class A { ... };
exports.b = 'constant';

Got it to work.
In file X.js I write:
constant B = "value";
class A {
}
modules.exports = {
A: A,
B: B
};
In the client code I use:
const X = require('./X');
let a = new X.A();

This is fairly easy to figure out. Now, let's say you have a code like this.
export class A { }
export const y= 5;
Which you basically want. But this is same as
class A { }
const x = 5;
exports.A = A;
exports.x = 5;
Now, you can figure it out also. open up babel repl and paste your ES6 code there. It will give you the ES5 equivalent in the right pane.
I pasted that ES6 code and got back
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var A = exports.A = function A() {
_classCallCheck(this, A);
};
var y = exports.y = 5;
Don't worry about _classCallCheck it is just a safeguard so that you cannot just call A() instead of new A()

Related

How can I declare variable for a module in TypeScript?

I have two files: index.ts and A.ts
A.ts:
export default class {
do() {
console.log(someVar);
}
}
index.ts:
import A from './A';
function printIt(param) {
let someVar = param;
let a = new A();
a.do();
}
printIt('wow'); // Console output: wow
printIt('123'); // Console output: 123
Is it real to declare someVar for A.ts from index.ts without wrapping A class?
I know that Node.JS wrappes all modules in (function (exports, require, module, __filename, __dirname, process, global) { }: How to change the Node.js module wrapper?
I tried to make a custom require function and pass my var like an argument. But I don't understand how can I make own require function in TypScript. Are there any ideas?
The scope of variables depends on where they are defined, not where they are called. this is on purpose, so you do not accidentally call on variables you did not know about being in the same scope as your function's invocation.
You must explicitly tell the code you want to pass this new variable into it, either just like Lux showed, or through passing it to the function like:
export default class {
do(someVar) {
console.log(someVar);
}
}
function printIt(param) {
let someVar = param;
let a = new A();
a.do(someVar);
}
what you're trying to do is akin to having everything be a global variable.
if you MUST do this (you shouldn't), there is one way you can.
export default class {
do() {
console.log(global.someVar);
}
}
function printIt(param) {
global.someVar = param;
let a = new A();
a.do();
}
There's many reasons why you do not want to do global variables, here are some
Edits after clarification:
So the "this" keyword inside of a module refers to the module's global scope, so I tried the following snippet:
// modA.js
const moduleContext = this
class ExportedClass {
printer() {
console.log(moduleContext.someVar)
}
}
module.exports = { ExportedClass }
//modB.js
let A = require("./modA")
A.someVar = "hello world"
let obj = new A.ExportedClass()
obj.printer()
and it seems the context was removed, the same thing with ES6 imports using mjs files, what did Work however is this:
//modA.js
function printer() {
console.log(this.someVar)
}
module.exports = { printer }
//modB.js
let A = require("./modA")
A.someVar = "hello world"
A.printer()
it seems moduleContext points to the old module context object, and the new imported module has a different context object.
This still seems like a bad idea though, you're better off structuring your code so that you export a constructing function, that takes whatever needs to be "global" for that scope, and sets it inside.
What are you trying to do? The seperation for module is on purpose, so the scope of everything remains.
Next, you have a typo: it should probably be let a = new A(); not let a = new A;.
But why dont you just pass the variable as an argument to the constructor of your A class?
export default class {
someVar: string;
constructor(someVar) {
this.someVar = someVar;
}
do() {
console.log(this.someVar);
}
}
now you can just do
function printIt(param) {
let someVar = param;
let a = new A(someVar);
a.do();
}

Sinon stub doesn't seem to work when object destructuring is used

Let's say you have a method called myMethod in the module myModule which is looking like this:
function myMethod() {
return 5;
}
module.exports.myMethod = myMethod;
Now if I want to stub this method to return 2 instead of 5 with Sinon I would write
const myModule = require('path/myModule');
sinon.stub(myModule, 'myMethod').returns(2);
Now in the place where you actually call the method you happen to import the method like this with object destruction
const { myMethod } = require('path/myModule');
console.log(myMethod()); // Will print 5
If you do that, myMethod is actually not stubbed and won't return 2 but 5 instead.
If you instead require again the module and use the function from the required module it will work
const myModule= require('path/myModule');
console.log(myModule.myMethod()); // Will print 2
Is there anyone who has a solution to this other than just changing the way I import my functions?
This is possible.
Just note that as soon as this runs:
const { myMethod } = require('./lib');
...it will remember whatever myMethod was at that moment.
So, you just have to make sure you set up the stub before that code runs.
So for this lib.js:
function myMethod() {
return 5;
}
module.exports.myMethod = myMethod;
and this code.js:
const { myMethod } = require('./lib');
console.log(myMethod());
you would just need to do this:
const sinon = require('sinon');
const myModule = require('./lib');
sinon.stub(myModule, 'myMethod').returns(2); // set up the stub FIRST...
require('./code'); // ...THEN require the code (prints "2")
The stubbed myMethod will have a different reference than the original method. In the destructuring example, you are setting the reference before it can be stubbed.
// cannot be stubbed
const { myMethod } = require('path/myModule');
// can be stubbed
const myModule = require('path/myModule');
myModule.myMethod();
Check out this similar question for more details

How to create node.js module using Typescript

The very simple module that I've created to test the viability of this endeavor. Here is the beginning of SPServerApp.ts:
class SPServerApp {
public AllUsersDict: any;
public AllRoomsDict: any;
constructor () {
this.AllUsersDict = {};
this.AllRoomsDict = {};
}
}
module.exports = SPServerApp();
Then in my app, I have this require statement:
var serverapp = require('./SPServerApp');
I then try to access one of the dictionaries like so:
serverapp.AllUsersDict.hasOwnProperty(nickname)
But get the error:
TypeError: Cannot read property 'hasOwnProperty' of undefined
Can anybody see what I am doing wrong here?
Thanks, E.
The problem is that you forgot the 'new' keyword when calling the constructor. The line should read:
module.exports = new SPServerApp();
If you don't use new your constructor will be treated as a normal function and will just return undefined (since you did not return anything explicitly). Also 'this' will not point to what you expect within the constructor.
Omitting new in Node is actually quite common. But for this to work you have to explicitly guard against new-less calls in the constructor like so:
constructor () {
if (! (this instanceof SPServerApp)) {
return new SPServerApp();
}
this.AllUsersDict = {};
this.AllRoomsDict = {};
}
BTW, in TypeScript you can also use module syntax. The TS compiler will translate this into the export/require statements. With ES6 style modules your example would look like this:
export class SPServerApp {
public AllUsersDict: any;
public AllRoomsDict: any;
constructor () {
this.AllUsersDict = {};
this.AllRoomsDict = {};
}
}
export var serverapp = new SPServerApp();
In your other TS file you just import:
import { serverapp } from './SPServerApp';
serverapp.AllUsersDict.hasOwnProperty('something');

Where does the "use strict" go when using TypeScript and AMD Modules

I am using TypeScript version 1.0.1.0
When using TypeScript and AMD modules together, where exactly should I write the "use strict" statement? Should it go above or below the imports?
I can write it above the imports, so that this TypeScript code:
"use strict";
import Backbone = require('backbone');
class MyClass extends Backbone.View<Backbone.Model> { }
export = MyClass;
results in this JavaScript with the statement at the top of the file:
"use strict";
var __extends = this.__extends || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
define(["require", "exports", 'backbone'], function(require, exports, Backbone) {
var MyClass = (function (_super) {
__extends(MyClass, _super);
function MyClass() { _super.apply(this, arguments); }
return MyClass;
})(Backbone.View);
return MyClass;
});
Or I can put the "use strict" statement below my imports. So that this TypeScript:
import Backbone = require('backbone');
"use strict";
class MyClass extends Backbone.View<Backbone.Model> { }
export = MyClass;
Results in this Javascript with the statement at the top of the RequireJS function declaration:
var __extends = this.__extends || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
define(["require", "exports", 'backbone'], function(require, exports, Backbone) {
"use strict";
var MyClass = (function (_super) {
__extends(MyClass, _super);
function MyClass() { _super.apply(this, arguments); }
return MyClass;
})(Backbone.View);
return MyClass;
});
Which one is correct? TSLint does not report a violation even when the statement is missing entirely. Is that perhaps a bug in TSLint?
The first variation results in whole-script strictness:
"use strict";
import Backbone = require('backbone');
class MyClass extends Backbone.View<Backbone.Model> { }
export = MyClass;
The second limits the scope of strictness to just the (generated) function:
import Backbone = require('backbone');
"use strict";
class MyClass extends Backbone.View<Backbone.Model> { }
export = MyClass;
In practise, it makes little difference in your case as it is only difference between the strict declaration including the auto-generated "extends" code or not - and the auto-generated code is strict-compliant.

Writing a javascript library

I want to write a JS library and handle it like this:
var c1 = Module.Class();
c1.init();
var c1 = Module.Class();
c2.init();
And of course, c1 and c2 can not share the same variables.
I think I know how to do this with objects, it would be:
var Module = {
Class = {
init = function(){
...
}
}
}
But the problem is I can't have multiple instances of Class if I write in this way.
So I'm trying to achieve the same with function, but I don't think I'm doing it right.
(function() {
var Module;
window.Module = Module = {};
function Class( i ) {
//How can "this" refer to Class instead of Module?
this.initial = i;
}
Class.prototype.execute = function() {
...
}
//Public
Module.Class = Class;
})();
I don't have a clue if it's even possible, but I accept suggestions of other way to create this module.
I don't know if it's relevant also, but I'm using jQuery inside this library.
Usage:
var c1 = Module.Class("c");
var c2 = Module.Class("a");
var n = c1.initial(); // equals 'c'
c1.initial("s");
n = c1.initial(); // equals 's'
Module Code:
(function(window) {
var Module = window.Module = {};
var Class = Module.Class = function(initial)
{
return new Module.Class.fn.init(initial);
};
Class.fn = Class.prototype = {
init: function(initial) {
this._initial = initial;
},
initial: function(v){
if (v !== undefined) {
this._initial = v;
return this;
}
return this._initial;
}
};
Class.fn.init.prototype = Class.fn;
})(window || this);
This is using the JavaScript "Module" Design Pattern; which is the same design pattern used by JavaScript libraries such as jQuery.
Here's a nice tutorial on the "Module" pattern:
JavaScript Module Pattern: In-Depth

Resources