diff --git a/lib/internal/modules/esm/resolve.js b/lib/internal/modules/esm/resolve.js index f9673a3ed54571..2ec53365373e86 100644 --- a/lib/internal/modules/esm/resolve.js +++ b/lib/internal/modules/esm/resolve.js @@ -246,8 +246,34 @@ function finalizeResolution(resolved, base, preserveSymlinks) { throw err; } - const stats = internalFsBinding.internalModuleStat(toNamespacedPath(StringPrototypeEndsWith(path, '/') ? - StringPrototypeSlice(path, -1) : path)); + let stats; + if (getOptionValue('--experimental-typescript')) { + if (StringPrototypeEndsWith(path, '/')) { + path = StringPrototypeSlice(path, 0, -1); + } + // Try to add .ts extension + let attemptTsPath = path; + if (!StringPrototypeEndsWith(attemptTsPath, '.ts')) { + attemptTsPath += '.ts'; + } + + stats = internalFsBinding.internalModuleStat(toNamespacedPath(attemptTsPath)); + switch (stats) { + case 0: + // Found the .ts file + path = attemptTsPath; + break; + case 1: + throw new ERR_UNSUPPORTED_DIR_IMPORT(path, fileURLToPath(base), String(resolved)); + default: + // In case we cannot find the .ts file, we fill fall back to js + stats = internalFsBinding.internalModuleStat(path); + break; + } + } else { + stats = internalFsBinding.internalModuleStat(toNamespacedPath(StringPrototypeEndsWith(path, '/') ? + StringPrototypeSlice(path, -1) : path)); + } // Check for stats.isDirectory() if (stats === 1) { diff --git a/test/fixtures/typescript/test-import-no-extension.ts b/test/fixtures/typescript/test-import-no-extension.ts new file mode 100644 index 00000000000000..54cea70c49ebd5 --- /dev/null +++ b/test/fixtures/typescript/test-import-no-extension.ts @@ -0,0 +1,2 @@ +import { a } from './a'; +console.log(a); \ No newline at end of file diff --git a/test/parallel/test-typescript.js b/test/parallel/test-typescript.js index 09a15a3bd32db9..7097a42589da09 100644 --- a/test/parallel/test-typescript.js +++ b/test/parallel/test-typescript.js @@ -45,3 +45,17 @@ test('execute a typescript with node_modules', async () => { stdout: 'Hello, TypeScript!\n', }); }); + +test('execute a typescript file with imports with no extensions', async () => { + const result = await spawnPromisified(process.execPath, [ + '--experimental-typescript', + fixtures.path('typescript/test-import-no-extension.ts'), + ]); + + deepStrictEqual(result, { + code: 0, + signal: null, + stderr: '', + stdout: 'Hello, TypeScript!\n', + }); +});