How can I declare variable for a module in TypeScript? - node.js

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();
}

Related

Javascript. What is the functional equivalent for class constructors?

Class constructor initializes and create objects/functions in a class. If I'm using functions, how would I initialize a function within the function?
This is the simple class
export default class MainProcess{
constructor() {
this.isReady = false
this.init()
}
init() {
this.setupApplicationMenu()
this.initWindowManager()
this.getIcons()
}
}
how can I initiate a MainPRocess Function?
While I'm not entirely sure I understand the question, I think you're asking "How can I create a function in a way that's similar to how I'm used to writing classes, but without using the class keyword?" Here's an example of that:
function Example () {
this.value = 10;
// instance method
this.print = function () {
console.log(this.value);
}
}
// static method
Example.printHello = function () {
console.log('hello world');
}
const example1 = new Example();
example1.print(); // 10
example1.value = 20;
example1.print(); //20
console.log(Object.getPrototypeOf(example1).constructor.name); // "Example"
const example2 = new Example();
example2. print(); //10
Example.printHello(); // "hello world"
Functions are part of the class. Classes are a grouping of functions(methods) and data(as properties). These functions are used to modify properties.
In the above example, you created a class MainProcess with some functions. However, functions defined in the init method is not present. The compiler will throw an error.
constructor is a special method used to create an object with that class.
If I'm using functions, how would I initialize a function within the
function?
It seems you are mixing two concepts function constructors in JS and Classes which are introduced later. Class is nothing, but a syntactic sugar on function constructor. JS is a prototype-based language.
difference b/w function and function constructor?
Functions created with the Function constructor do not create closures to their creation contexts; they always are created in the global scope. When running them, they will only be able to access their own local variables and global ones, not the ones from the scope in which the Function constructor was created. This is different from using Global_Objects/eval with code for a function expression.
var x = 10;
function createFunction1() {
var x = 20;
return new Function('return x;'); // this |x| refers global |x|
}
function createFunction2() {
var x = 20;
function f() {
return x; // this |x| refers local |x| above
}
return f;
}
var f1 = createFunction1();
console.log(f1()); // 10
var f2 = createFunction2();
console.log(f2()); // 20
I highly recommend you first understand the how JS has implemented class in it.

Does nodejs requires bind class method?

I am using node 12 in my project. Back to 2 years ago, I remember I need to bind method for class instance method like below:
class Logger {
constructor () {
this.printName = this.printName.bind(this);
}
printName (name = 'there') {
this.print(`Hello ${name}`);
}
print (text) {
console.log(text);
}
}
But recently I found I don't need to call bind in the constructor. Does the latest node version support auto-bind already?
The behavior hasn't changed. The situation in which you need to .bind is when the instance's printName method would otherwise get called without a calling context. For example:
class Logger {
printName (name = 'there') {
this.print(`Hello ${name}`);
}
print (text) {
console.log(text);
}
}
const l = new Logger();
const fn = l.printName;
fn();
or with, instead of fn:
setTimeout(l.printName)
or with:
button.addEventListener('click', l.printName)`
In all of these situations, an error will be thrown if you don't use .bind, because the method gets called without a calling context - but the calling context of the Logger instance is needed for this to refer to the instance, so that this.print refers to the print method of the instance.
This sort of thing has always been true in Javascript. Nothing's changed in the past few years, except that it's now a bit easier to bind - you can use new class field syntax instead of having a constructor:
class Logger {
printName = (name = 'there') => {
this.print(`Hello ${name}`);
}
print (text) {
console.log(text);
}
}
const l = new Logger();
const fn = l.printName;
fn();

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 define a class AND constants in a CommonJS module

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()

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');

Resources