I looked at similar questions/answers but they are different from my question or my setup.
I've a class B that extends class A and writing a test for the class B.
src folder
src/a/A.js
export default class A {
// implementation
}
src/b/B.js
import A from "../a/A" // -> SyntaxError: Cannot use import statement outside a module
export default class B extends A {
constructor() {
}
}
test folder
describe("BTest", function(){
let assert = require("assert");
describe("testConstructor", function(){
let B = require("../src/b/B");
let b = new B();
assert(b != null)
});
});
You appear to be running in a node environment. Node doesn't support import/export. You’ll need to either use require and module.exports or transpile your code using Babel.
Related
I have following code:
export class Utils{
constructor() {
this.dateFormat = "MM-DD-YY";
}
static getFormat() {
return this.dateFormat;
}
}
when I am trying to import this class to other file and try to call the static method gteFormat it return undefined.
Here is how I am doing it:
import * as Utils from "./commons/Utils.js";
class ABC {
init(){
console.log(Utils.Utils.getFormat());// gives undefined
}
}
How can I make this static method return the dateFormat property?
If you are conceptually working with a bunch of functions, you can consider relying on the module scope itself for privacy, rather than the class structure. Then you can export functions or values directly. Like
const dateFormat = "MM-DD-YY";
export function getFormat() {
return dateFormat;
}
with usage like
import * as Utils from "./commons/Utils.js";
console.log(Utils.getFormat())
or even
import { getFormat } from "./commons/Utils.js";
console.log(getFormat())
or if it's literally a constant you can export it directly
export const DATE_FORMAT = "MM-DD-YY";
then
import { DATE_FORMAT } from "./commons/Utils.js";
console.log(DATE_FORMAT);
Exporting a class with a bunch of static methods is a very Java-y way to write it, and the class itself adds nothing.
Constructors are for instances
Think about it: a constructor is called when an instance is created, setting static defaults is probably better done elsewhere, for example when declaring the static variable
class Utils {
static dateFormat = "MM-DD-YY";
static getFormat() {
return this.dateFormat;
}
}
console.log(Utils.getFormat())
If, for some reason, you have to set this in a constructor anyways, the correct syntax will be Utils.dateFormat = "...". Funny side fact is that you can use this when reading (in the return statement). However, you would still have to instanciate an instance of Utils in order for dateFormat to be sth. other than undefined:
class Utils {
static dateFormat;
constructor() {
Utils.dateFormat = "MM-DD-YY"; // use Utils.dateFormat when writing
}
static getFormat() {
return this.dateFormat; // use whatever you like when reading... :/
}
}
console.log(`Before instanciating: ${Utils.getFormat()}`);
var dummy = new Utils();
console.log(`After instanciating: ${Utils.getFormat()}`);
A sidenote on your import statement
you could avoid having to call Utils.Utils.getFormat() everytime, which looks a bit weird, by refactoring your import-statement like so:
// import * as Utils from "./commons/Utils.js";
import { Utils } from "./commons/Utils.js";
class ABC {
init(){
//console.log(Utils.Utils.getFormat());
console.log(Utils.getFormat());
}
}
Currently, I have 4 Child Classes each in their own file. I'm requiring them all in the same file. I am wondering if I can contain all 4 of those classes in a single module. Currently, I'm importing them like this
var Jack = require('./Jack.js');
var JackInstance = new Jack();
var Jones = require('./Jones.js');
var JonesInstance = new Jones();
I'd like to import them like this
var People = require('./People.js');
var JackInstance = new People.Jack();
Or even
var Jack = require('./People.js').Jack;
var JackInstance = new Jack();
My classes are defined like so
class Jack{
//Memeber variables, functions, etc
}
module.exports = Jack;
You can export multiple classes like this:
e.g. People.js
class Jack{
//Member variables, functions, etc
}
class John{
//Member variables, functions, etc
}
module.exports = {
Jack : Jack,
John : John
}
And access these classes as you have correctly mentioned:
var People = require('./People.js');
var JackInstance = new People.Jack();
var JohnInstance = new People.John();
You can also do this in a shorter form, using destructuring assignments (which are supported natively starting from Node.js v6.0.0):
// people.js
class Jack {
// ...
}
class John {
// ...
}
module.exports = { Jack, John }
Importing:
// index.js
const { Jack, John } = require('./people.js');
Or even like this if you want aliased require assignments:
// index.js
const {
Jack: personJack, John: personJohn,
} = require('./people.js');
In the latter case personJack and personJohn will reference your classes.
A word of warning:
Destructuring could be dangerous in sense that it's prone to producing unexpected errors. It's relatively easy to forget curly brackets on export or to accidentally include them on require.
Node.js 12 update:
Lately ECMAScript Modules received an extended support in Node.js 12.*, introducing the convenient usage of import statement to accomplish the same task (currently Node should be started with a flag --experimental-modules in order to make them available).
// people.mjs
export class Jack {
// ...
}
export class John {
// ...
}
Notice that files that adhere to modules convention should have an .mjs extension.
// index.mjs
import {
Jack as personJack, John as personJohn,
} from './people.mjs';
This is much better in a sense of robustness and stability, as an attempt to import non-existing export from the module will throw an exception similar to:
SyntaxError: The requested module 'x' does not provide an export named
'y'
What's the ES6 equivalent for module.exports
I want to get the value of foo from an import statement
module.exports = {
foo: function (a) {
}
}
Tried:
export default {
foo: function (a) {
}
}
The way first one is imported is using:
var file;
var filename = root + "/" + fileStats.name;
file = require(path.resolve(filename));
I want to use ES6 import statement. I read somewhere that this isn't supported however would like to still know if there's a work around this.
Not sure what you're trying to do because in the code you supplied you did not consume the actual foo method from the object you imported.
But if I understand correctly, you could achieve this in one of 2 ways:
export default function foo(a) { };
and consume the module with:
import foo from './<filename>.js';
Or alternatively, don't use the default export:
export function foo(a) {};
and consume with:
import { foo } from './<filename>.js';
I am using Babel to compile some ES6 JavaScript down to ES5. I am having some trouble with my code because my modules are being evaluated in an undefined order.
Let's say I have a modules:
// a.js
class A {
constructor() {
this.prop = window.randomProperty;
console.log("Prop " + this.prop);
}
}
const a = new A();
export default a;
This module relies on window.randomProperty to be set before it can instantiate itself.
Now I have a main file:
// main.js
import "babel-polyfill"; // Not sure if this is relevant
window.randomProperty = function() { return "hi"; };
console.log("randomProperty set");
import A from "a";
The console output of this is:
Prop undefined
randomProperty set
How can I have the code execute in the correct order?
import statements are hoisted, so imports are loaded before your code is executed. To execute it in order you want, you should use other module loader such as using require.
const A = require("a");
Imports are loaded (and executed, unless cyclic) before the module is executed statically. In your case, a.js will be loaded before main.js is executed.
If you have dependencies, you should declare them explicitly:
// random_prop.js
window.randomProperty = function() { return "hi"; };
console.log("randomProperty set");
// a.js
import "random_prop";
const a = {
prop: window.randomProperty;
}
console.log("Prop " + a.prop);
export {a as default}
// main.js
import "babel-polyfill"; // Not sure if this is relevant
import a from "a";
console.log(a.prop);
Of course, you could also import the random_prop.js in main.js before a.js, and it would work in this simple setting, but I would not recommend relying on side effects like that.
Your problem lies in where you instantiate A, try doing it in main.js. Check this out:
// a.js
class A {
constructor() {
this.prop = window.randomProperty;
console.log("Prop " + this.prop);
}
}
// do not instantiate here
// const a = new A();
export default a;
Just make sure you create the object here:
// main.js
import A from "a";
window.randomProperty = function() { return "hi"; };
console.log("randomProperty set");
const a = new A();
The reason is, when you import a module, it will invoke any methods that are not tied to a function or class definition.
Hope this helps!
There is something I am not getting in TypeScript when it comes to declaration files and 3rd party libraries written in pure Javascript. Let's say I have the following Javascript class:
$ cat SomeClass.js
var SomeClass = (function () {
function SomeClass() {
}
SomeClass.prototype.method1 = function () {
return "some string";
};
return SomeClass;
})();
exports.SomeClass = SomeClass;
And I want to get type checking for it, so I create declaration file like this:
$ cat test.d.ts
class SomeClass {
public method1(): string;
}
Then I want to use the class and declaration file in some code:
$ cat main.ts
///<reference path="./test.d.ts"/>
import ns = module("./SomeClass");
function test(): string {
var sc = new ns.SomeClass();
return sc.method1();
}
When I try to compile it, I get this:
$ tsc main.ts
main.ts(2,19): The name '"./SomeClass"' does not exist in the current scope
main.ts(2,19): A module cannot be aliased to a non-module type
main.ts(5,16): Expected var, class, interface, or module
From what I can tell, the import statement requires an actual TypeScript class to exist and the reference statement isn't enough to help the compiler figure out how to handle it.
I tried changing it to
import ns = module("./test.d");
But no dice either.
The only way I can get this to actually compile and run is to use the require statement instead of import, like this:
$ cat main.ts
///<reference path="./node.d.ts"/>
///<reference path="./test.d.ts"/>
var ns = require("./SomeClass");
function test(): string {
var sc = new ns.SomeClass();
return sc.method1();
}
The problem with this code is that TypeScript is not running any type checking. In fact, I can totally remove the line
///<reference path="./test.d.ts"/>
and it doesn't change anything.
However, if I remove the require statement, I can get type checking, but the code blows up at runtime because there is no require statement.
$ cat main.ts
///<reference path="./test.d.ts"/>
function test(): string {
var sc = new SomeClass();
return sc.method1();
}
test();
$ node main.js
main.js:2
var sc = new SomeClass();
^
ReferenceError: SomeClass is not defined
...
cat test.d.ts
declare module "SomeClass.js" {
class SomeClass {
method1(): string;
}
}
cat Main.ts
///<reference path="test.d.ts"/>
import ns = module("SomeClass.js");
function test() {
var sc = new ns.SomeClass();
return sc.method1();
}
tsc Main.ts --declarations
cat Main.js
var ns = require("SomeClass.js")
function test() {
var sc = new ns.SomeClass();
return sc.method1();
}
cat Main.d.ts
import ns = module ("SomeClass.js");
function test(): string;