14

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

1

2 Answers 2

14

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"
}
Sign up to request clarification or add additional context in comments.

5 Comments

This is too experimental and causes other issues in my application.
This is so weird, I don't need to do it with vite based application but need it for normal application
I've found success using an npm package called 'extensionless'
still, this does not remove the errors in your IDE. e.g. webstorm will still complain. just use "moduleResolution": "node" in your tsconfig.json and you're good
@Unispaw If you are going to recommend "moduleResolution": "node" to people, at least clarify that its a deprecated value that will cause more issues in future. To anyone else reading, if possible, always use "node16" or greater
-5

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",
    // ...
  },
  // ...
}

8 Comments

But I want to use ES modules, not CommonJS modules. And I need to have "type": "module" set in my package.json since I deploy this at Heroku which needs this when it executes the transpiled JavaScript.
There is no way to use ES modules without the file extension. It's part of how it works. Check out the documentation: typescriptlang.org/docs/handbook/esm-node.html
But e.g. create-react-app accomplishes this with Webpack, and Vite accomplishes this with esbuild. Surely there is some tweak or setting or hack to be able to leave it out. Or a way to use Parcel or some simple build tool like Gulp to accomplish this. It's not a blocker, it's just a non-optimal leaky abstraction: having to import non-existent .js modules when developing a TypeScript app.
Do you realize that .ts files are not run? They are compiled into .js files and that's what you actually run.
Yes, of course I realize that, but I would like to have the TypeScript programming environment that I have in e.g. React sites created with Vite or create-react-app where you don't provide the extension. There must be some kind of easy way to e.g. add the .js extension during the build process.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.