25

Very simple test of async/await and I have a module that includes simple class to implement a delay function

mymodule.ts:

export class foo {

    public async delay(t: number) {
                console.log("returning prmise");
                return new Promise( resolve => setTimeout(resolve, t));
    };
};

Simple top-level TypeScript file to call the function:

hello.ts:

import { foo } from './mymodule'

let f = new foo();

console.log("start");
await f.delay(4000);
console.log("done");here

This builds fine but when I run the resulting hello.js with Node (node hello.js) I get:

Error [ERR_MODULE_NOT_FOUND]: Cannot find module 'E:\tsdev\test\out\mymodule' imported from E:\tsdev\test\out\hello.js
Did you mean to import ../mymodule.js?
    at new NodeError (node:internal/errors:399:5)
    at finalizeResolution (node:internal/modules/esm/resolve:326:11)
    at moduleResolve (node:internal/modules/esm/resolve:945:10)
    at defaultResolve (node:internal/modules/esm/resolve:1153:11)
    at nextResolve (node:internal/modules/esm/loader:163:28)
    at ESMLoader.resolve (node:internal/modules/esm/loader:838:30)
    at ESMLoader.getModuleJob (node:internal/modules/esm/loader:424:18)
    at ModuleWrap.<anonymous> (node:internal/modules/esm/module_job:77:40)
    at link (node:internal/modules/esm/module_job:76:36) {
  code: 'ERR_MODULE_NOT_FOUND'
}

If I add ".js" to make the import import { foo } from './mymodule.js' it also builds just fine and now the application works as expected:

E:\tsdev\test\out>node hello.js
start
returning prmise
done

I tried various changes to tsconfig.json and package.json files.

4

1 Answer 1

33

If you want to use the official TypeScript compiler to generate JavaScript, you have to add the extension because

  1. Node.js refuses to allow extensionless relative imports
  2. TypeScript refuses to add import extensions at compile time

If you want or need to write extensionless imports in TypeScript, you need a bundler or an alternative build tool that can add the .js extensions. For example, you can transpile TypeScript to JavaScript using Babel and babel-plugin-add-import-extension.

However, you'll still need TypeScript (tsc) itself to do type checking and generate type declaration files, so you'll need a tsconfig.json with compilerOptions.moduleResolution set to "Bundler".

Here's my configuration for a library that targets Node.js 18.

.babelrc:

{
  "presets": [
    [
      "@babel/env",
      {
        "modules": false,
        "targets": {
          "node": "18"
        }
      }
    ],
    "@babel/typescript"
  ],
  "plugins": ["add-import-extension"]
}

tsconfig.json

{
  "extends": "@tsconfig/strictest/tsconfig.json",
  "compilerOptions": {
    "allowJs": false,
    "checkJs": false,
    "declaration": true,
    "declarationMap": true,
    "emitDeclarationOnly": true,
    "lib": ["ES2022"],
    "module": "ES2022",
    "moduleResolution": "Bundler",
    "sourceMap": true,
    "target": "ES2022"
  }
}

package.json scripts:

{
    "build": "run-p -s build:*",
    "build:main": "babel -x .ts -d dist src",
    "build:types": "tsc",
}

and some devDependencies:

{
    "@babel/cli": "^7.22.15",
    "@babel/preset-typescript": "^7.22.15",
    "babel-plugin-add-import-extension": "^1.6.0",
    "npm-run-all": "^4.1.5",
    "typescript": "^5.2.2"
}
Sign up to request clarification or add additional context in comments.

3 Comments

I've ran into OP's issue and, wow, what an incredibly complicated solution for something that should be fixed on TS side :(
@SilviuBurcea this level of complexity is par for the course in the world of JavaScript.
How to exclude *.d.ts?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.