Search code examples
node.jstypescriptimportimporterror

When cannot a local module (.ts file) be found when imported?


I am writing my first node.js program (I wrote over the years some JS/TS frontend code, as well as Go, Python), and after some first basic tests I started to modularize my code (to group it in logical chunks).

I have an exported getConfig() function in D:\W\dev-perso\hass-monitoring\src\config.ts and would like to use it in my D:\W\dev-perso\hass-monitoring\src\main.ts one:

import { getConfig } from "./config"

getConfig()

I get the error

PS D:\W\dev-perso\hass-monitoring\src> ts-node-esm .\main.ts
C:\Users\W\AppData\Roaming\npm\node_modules\ts-node\dist-raw\node-internal-modules-esm-resolve.js:366
    throw new ERR_MODULE_NOT_FOUND(
          ^
CustomError: Cannot find module 'D:\W\dev-perso\hass-monitoring\src\config' imported from D:\W\dev-perso\hass-monitoring\src\main.ts

The documentation explains how the actual import is done, and this mirrors my setup:

For example, an import statement like import { b } from "./moduleB" in /root/src/moduleA.ts would result in attempting the following locations for locating "./moduleB":

/root/src/moduleB.ts
(...)

In that case why do I get the Cannot find module ... error when the .ts file is present where expected?


For reference, my tsconfig.json:

{
    "compilerOptions": {
        "module": "es2022",
        "esModuleInterop": true,
        "target": "es2017",
        "moduleResolution": "node",
        "sourceMap": true,
        "outDir": "dist",
        "typeRoots": [
            "node_modules/@types"
        ],
        "types": [
            "node"
        ]
    },
    "lib": [
        "es2015"
    ],
    "include": [
        "./src/*.ts",
        "./src/**/*.ts",
    ]
}

Solution

  • I "solved" the issue by adding .js to the imported file (import { getConfig } from "./config.js") but I have no idea why it works that way.

    I can wildly guess that, ultimately, the file that is processed by JS is a .js file generated from the .ts one but it seems really weird to import it that way (but it works).

    EDIT: this is actually documented:

    (...) relative import paths need to use extensions. As a result, it will have to be rewritten to use the extension of the output of foo.ts - so bar.ts will instead have to import from ./foo.js.