Edward Tanguay
Edward Tanguay

Reputation: 193282

How to force TypeScript in Node to not require .js extension when importing ES6 modules?

I have a Node API set up with TypeScript working fine.

However, to import an ES6 extension, I have to include .js even though the file is .ts.

Using the .ts extension or leaving out the extension in the import line causes the error:

CustomError: Cannot find module 'C:\.....\src\models'

server.ts

import express from 'express';
import dotenv from 'dotenv';
import { user } from './models.js';

dotenv.config();

const app = express();
const PORT = process.env.PORT || 3049;

app.get('/', (req: express.Request, res: express.Response) => {
    res.send(user);
});

app.listen(PORT, () => {
    console.log(`listening on port http://localhost:${PORT}`);
});

models.ts

import { IUser } from './interfaces.js';

export const user: IUser = {
    firstName: "Hendrick",
    lastName: "Denzmann",
    accessGroups: ['loggedInUsers', 'members']
};

I start my app with this command in package.json:

"scripts": {
    "dev": "nodemon"
},

And here are my config files:

nodemon.json

{
    "watch": [""],
    "ext": "ts",
    "exec": "./node_modules/.bin/ts-node-esm src/server.ts"
}

tsconfig.json

{
    "compilerOptions": {
        "target": "es6",
        "allowSyntheticDefaultImports": true,
        "moduleResolution": "node",
        "module": "esnext",
        "outDir": "build"
    }
}

What do I need to change so that I can import my ES6 modules without an extension, like this: import { user } from './models';?

Upvotes: 13

Views: 12053

Answers (2)

blvz
blvz

Reputation: 1493

You'll need to tell the node binary to stop requiring extensions. Currently this is done through an experimental flag, --experimental-specifier-resolution=node. Then you can use ts-node as a loader instead.

Basically, just change the exec part of your nodemon.json to this:

{
  "watch": [""],
  "ext": "ts",
  "exec": "node --experimental-specifier-resolution=node --loader ts-node/esm src/server.ts"
}

Upvotes: 14

lepsch
lepsch

Reputation: 10319

Most probably ESM module is enabled in the package.json file with the following configuration.

package.json

{
  ...
  "type": "module"
  ...
}

Just remove it. If it's not possible to remove it check this other answer Force TypeScript to generate export/imports with the ".js" extension; running Node 16?

Also change the tsconfig.json's compilerOptions module from esnext to commonjs.

tsconfig.json

{
  "compilerOptions": {
    "module": "commonjs",
    // ...
  },
  // ...
}

Upvotes: -4

Related Questions