152

I defined a class in a module:

"use strict";

var AspectTypeModule = function() {};
module.exports = AspectTypeModule;

var AspectType = class AspectType {
    // ...    
};

module.export.AspectType = AspectType;

But I get the following error message:

TypeError: Cannot set property 'AspectType' of undefined
    at Object.<anonymous> (...\AspectType.js:30:26)
    at Module._compile (module.js:434:26)
    ....

How should I export this class and use it in another module? I have seen other SO questions, but I get other error messages when I try to implement their solutions.

Alexis Wilke
  • 19,179
  • 10
  • 84
  • 156
Jérôme Verstrynge
  • 57,710
  • 92
  • 283
  • 453
  • 2
    In ES6 you don't need `'use strict'` in a module or class; its the default behaviour. Ref. 10.2.1 Strict Mode Code – Jason Leach Nov 14 '16 at 00:25

9 Answers9

158
// person.js
'use strict';

module.exports = class Person {
   constructor(firstName, lastName) {
       this.firstName = firstName;
       this.lastName = lastName;
   }

   display() {
       console.log(this.firstName + " " + this.lastName);
   }
}

 

// index.js
'use strict';

var Person = require('./person.js');

var someone = new Person("First name", "Last name");
someone.display();
Alexis Tyler
  • 1,394
  • 6
  • 30
  • 48
sitrakay
  • 1,731
  • 1
  • 9
  • 3
  • 5
    @sitrakay you should really add an explanation of how this fixes the question. – Alexis Tyler Feb 24 '17 at 06:27
  • this gives the error: Uncaught TypeError: Cannot assign to read only property 'exports' of object '#' how come this is upvoted so much? – henon Nov 24 '18 at 15:45
  • 1
    I think putting an entire class definition inside the exports assignment is an anti pattern when a single line at the end should do the same thing. – user1944491 May 08 '20 at 16:11
  • in my case, the `display` function is not exported unless in the constructor I wrote `this.display = display`, any idea why? – Zennichimaro Sep 18 '20 at 05:19
135

If you are using ES6 in Node 4, you cannot use ES6 module syntax without a transpiler, but CommonJS modules (Node's standard modules) work the same.

module.export.AspectType

should be

module.exports.AspectType

hence the error message "Cannot set property 'AspectType' of undefined" because module.export === undefined.

Also, for

var AspectType = class AspectType {
    // ...    
};

can you just write

class AspectType {
    // ...    
}

and get essentially the same behavior.

loganfsmyth
  • 156,129
  • 30
  • 331
  • 251
74

With ECMAScript 2015 you can export and import multiple classes like this

class Person
{
    constructor()
    {
        this.type = "Person";
    }
}

class Animal{
    constructor()
    {
        this.type = "Animal";
    }
}

module.exports = {
    Person,
    Animal
};

then where you use them:

const { Animal, Person } = require("classes");

const animal = new Animal();
const person = new Person();

In case of name collisions, or you prefer other names you can rename them like this:

const { Animal : OtherAnimal, Person : OtherPerson} = require("./classes");

const animal = new OtherAnimal();
const person = new OtherPerson();
Jonas Brandel
  • 1,265
  • 12
  • 7
  • 4
    Wrong. Reason: If you are using ES6 in Node 4, you cannot use ES6 module syntax without a transpiler, but CommonJS modules (Node's standard modules) work the same. (as per above) – AaronHS Apr 21 '18 at 15:42
  • 1
    Also you shouldn't declare two classes in the same file – ariel Sep 03 '18 at 20:16
  • It is okay to have "private-like" classes (that assist the single public class) to be in the same file, as long as the private classes aren't exported. It is also acceptable if you haven't yet refactored them into two files yet. When doing so, don't forget to split your tests to separate files too. Or just do what you need to for your situation. – TamusJRoyce Feb 17 '19 at 08:33
  • @AaronHS what is the exact difference to which you're referring? It's not clear in the "above" answer either. – user1944491 May 08 '20 at 16:13
21

Use

// aspect-type.js
class AspectType {

}

export default AspectType;

Then to import it

// some-other-file.js
import AspectType from './aspect-type';

Read http://babeljs.io/docs/learn-es2015/#modules for more details

Mulan
  • 129,518
  • 31
  • 228
  • 259
18

I simply write it this way

in the AspectType file:

class AspectType {
  //blah blah
}
module.exports = AspectType;

and import it like this:

const AspectType = require('./AspectType');
var aspectType = new AspectType();
14

class expression can be used for simplicity.

 // Foo.js
'use strict';

// export default class Foo {}
module.exports = class Foo {}

-

// main.js
'use strict';

const Foo = require('./Foo.js');

let Bar = new class extends Foo {
  constructor() {
    super();
    this.name = 'bar';
  }
}

console.log(Bar.name);
masakielastic
  • 4,540
  • 1
  • 39
  • 42
  • 4
    Just a warning, in Node this is subject to module loading order. So be careful with using this. If you switch the names of these files around the example wouldn't work. – Dustin Apr 11 '16 at 22:32
10

Several of the other answers come close, but honestly, I think you're better off going with the cleanest, simplest syntax. The OP requested a means of exporting a class in ES6 / ES2015. I don't think you can get much cleaner than this:

'use strict';

export default class ClassName {
  constructor () {
  }
}
Crates
  • 2,362
  • 2
  • 19
  • 15
  • 3
    Wrong. Reason: If you are using ES6 in Node 4, you cannot use ES6 module syntax without a transpiler, but CommonJS modules (Node's standard modules) work the same. (as per above) – AaronHS Apr 21 '18 at 15:41
  • 4
    Who the heck is still using Node 4? I think this is a valid answer for 99% of people. – Crates Jan 29 '19 at 16:20
  • 2
    It’s literally in the title of the question. – AaronHS May 10 '20 at 02:26
0

I had the same problem. What i found was i called my recieving object the same name as the class name. example:

const AspectType = new AspectType();

this screwed things up that way... hope this helps

shahar taite
  • 462
  • 6
  • 11
0

Sometimes I need to declare multiple classes in one file, or I want to export base classes and keep their names exported because of my JetBrains editor understands that better. I just use

global.MyClass = class MyClass { ... };

And somewhere else:

require('baseclasses.js');
class MySubclass extends MyClass() { ... }
Jelmer Jellema
  • 1,072
  • 10
  • 16
  • 1
    This is a bad way to do this... it **will** result in a collision some day. – Brad Oct 13 '17 at 18:22
  • Yeah well. No problem with collisions in owned projects. And if you purely import classes through require / module.exports, you're just shifting the problem to the module-names. – Jelmer Jellema Nov 30 '17 at 00:05
  • Stop trying to write PHP in JavaScript :P Jokes aside - as everyone else has said, this is just setting yourself up for problems later down the line. Globals are a very bad no good very very bad idea. – robertmain Jul 30 '18 at 15:39
  • 1
    They are for people not being able to track their own code. Don't forget the filenames used in require are also globals. The no-globals dogma has its limits too. – Jelmer Jellema Aug 07 '18 at 09:25
  • Well, @TimHobbs, the things kids say.. Stuff like "They just are, period." That is exactly the kind of arguments you hear from people in lack of real arguments. You know. Even NodeJs uses globals. There is not even a problem when you have a well defined framework with well documented globals. Nice to hear that after all this years of study, cum laude graduation and feeding myself and my family for 20 years now, it's just "what I want to do anyway". Give me an argument or stop acting like a kid. – Jelmer Jellema Dec 17 '18 at 10:06