TypeStrong / ts-node

TypeScript execution and REPL for node.js
https://typestrong.org/ts-node
MIT License
12.84k stars 534 forks source link

All of my node_modules return undefined #311

Closed mattdell closed 7 years ago

mattdell commented 7 years ago

Really struggling with this.

Test file is users.spec.js

import testHelper from '../test-helper';

const { chai, expect, baseUrl } = testHelper;

describe('users endpoint', () => {
  it('should get a response', (done) => {
    chai.request(baseUrl)
      .get('/users')
      .end((err, res) => {
        expect(res).to.have.status(200);
        done();
      });
  });
});

testHelper calls a file user.ts, which at the top says...

import mongoose from 'mongoose';

export interface IUserModel extends mongoose.Document {

When I run ts-node I get the following error

> mocha --opts tests/mocha.opts

/Users/mdell/Play/Repos/server/src/models/user.ts:23
const userSchema = new mongoose.Schema({
                               ^
TypeError: Cannot read property 'Schema' of undefined

The same thing happens if I try to call lodash in the same place.

import _ from 'lodash';

console.log('_ is', _);
console.log(_.sum([1, 2]));
> mocha --opts tests/mocha.opts

_ is undefined

/Users/mdell/Play/Repos/server/src/models/user.ts:4
console.log(_.sum([1, 2]));
             ^
TypeError: Cannot read property 'sum' of undefined

So it seems like tests that call files that call node_modules can't be run. What am I missing?

blakeembrey commented 7 years ago

This isn't a ts-node issue. You should check out the documentation for TypeScript's configuration. Namely, it would appear, you're either ignoring TypeScript errors or you've enabled allowSynthenticModules without understanding what it does. Finding these docs are a PITA, but you can find it in the original release notes: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-1-8.html. Node.js does not magically move default to the primary import so the import statement is wrong (getting undefined). Use import * as x from or import x = require('') to import CommonJS modules and remove that option if you intend to use node.

mattdell commented 7 years ago

This is good to know, and you're correct that I didn't fully understand allowSyntheticDefaultImports.

What I don't understand is why this works fine when I run it through webpack with ts-loader, but fails horribly when I simply want to run mocha with ts-node. 🤔

blakeembrey commented 7 years ago

Webpack probably supports that style of import, just like SystemJS does. Haven't tested it myself and I don't have your configuration to verify, but if it works - that would be why.

mattdell commented 7 years ago

Thanks for the help @blakeembrey. I've decided to stick with webpack since it works. It's a bit more involved than I wanted, but webpack suggests this method for testing: https://webpack.github.io/docs/testing.html#compile-and-test

webpack test.js /tmp/testBundle.js --target node
mocha /tmp/testBundle.js

Suits me for now. 😄

swashata commented 3 years ago

Setting esModuleInterop to true did the trick for me. Basically I was importing

import React from 'react';

const Component = React.forwardRef(...)

While I understand the problem in the above code, it is under a large codebase and changing all to something like

import { forwardRef } from 'react';

or

import * as React from 'react';

would be a large task at this moment. So I setup the tsconfig to support this.

{
    "compilerOptions": {
        "target": "esnext",
        "module": "CommonJS",
        "moduleResolution": "node",
        "lib": ["esnext", "dom", "dom.iterable"],
        "allowJs": false,
        "allowSyntheticDefaultImports": true,
        "esModuleInterop": true,
        "isolatedModules": true,
        "resolveJsonModule": true,
        "jsx": "react-jsx",
        "noEmit": true,
        "skipLibCheck": true,
        "strict": true,
        "baseUrl": ".",
    },
    "include": ["src", "styleguidist", "bin"]
}

I hope it helps.