diff --git a/lib/internal/modules/cjs/loader.js b/lib/internal/modules/cjs/loader.js index b18773a6ed8763..9f9e37692a5929 100644 --- a/lib/internal/modules/cjs/loader.js +++ b/lib/internal/modules/cjs/loader.js @@ -653,9 +653,13 @@ function getDefaultExtensions() { let extensions = ObjectKeys(Module._extensions); const tsEnabled = getOptionValue('--experimental-strip-types'); if (tsEnabled) { + // remove .ts and .cts from the default extensions + // to avoid extensionless require of .ts and .cts files. + // it behaves similarly to how .mjs is handled when --experimental-require-module + // is enabled. extensions = ArrayPrototypeFilter(extensions, (ext) => - ext !== '.ts' || Module._extensions['.ts'] !== loadTS || - ext !== '.cts' || Module._extensions['.ts'] !== loadCTS, + (ext !== '.ts' || Module._extensions['.ts'] !== loadTS) && + (ext !== '.cts' || Module._extensions['.cts'] !== loadCTS), ); } diff --git a/test/es-module/test-typescript-commonjs.mjs b/test/es-module/test-typescript-commonjs.mjs index 477e0633f78678..aa3550bbab95f3 100644 --- a/test/es-module/test-typescript-commonjs.mjs +++ b/test/es-module/test-typescript-commonjs.mjs @@ -18,8 +18,6 @@ test('require a .ts file with explicit extension succeeds', async () => { strictEqual(result.code, 0); }); -// TODO(marco-ippolito) This test should fail because extensionless require -// but it's behaving like a .js file test('eval require a .ts file with implicit extension fails', async () => { const result = await spawnPromisified(process.execPath, [ '--experimental-strip-types', @@ -30,13 +28,26 @@ test('eval require a .ts file with implicit extension fails', async () => { cwd: fixtures.path('typescript/ts'), }); - strictEqual(result.stderr, ''); - match(result.stdout, /Hello, TypeScript!/); - strictEqual(result.code, 0); + strictEqual(result.stdout, ''); + match(result.stderr, /Error: Cannot find module/); + strictEqual(result.code, 1); +}); + +test('eval require a .cts file with implicit extension fails', async () => { + const result = await spawnPromisified(process.execPath, [ + '--experimental-strip-types', + '--eval', + 'require("./test-cts-typescript")', + '--no-warnings', + ], { + cwd: fixtures.path('typescript/ts'), + }); + + strictEqual(result.stdout, ''); + match(result.stderr, /Error: Cannot find module/); + strictEqual(result.code, 1); }); -// TODO(marco-ippolito) This test should fail because extensionless require -// but it's behaving like a .js file test('require a .ts file with implicit extension fails', async () => { const result = await spawnPromisified(process.execPath, [ '--experimental-strip-types', @@ -44,9 +55,9 @@ test('require a .ts file with implicit extension fails', async () => { fixtures.path('typescript/cts/test-extensionless-require.ts'), ]); - strictEqual(result.stderr, ''); - match(result.stdout, /Hello, TypeScript!/); - strictEqual(result.code, 0); + strictEqual(result.stdout, ''); + match(result.stderr, /Error: Cannot find module/); + strictEqual(result.code, 1); }); test('expect failure of an .mts file with CommonJS syntax', async () => { diff --git a/test/fixtures/typescript/ts/test-cts-typescript.cts b/test/fixtures/typescript/ts/test-cts-typescript.cts new file mode 100644 index 00000000000000..45d056b9c94e3a --- /dev/null +++ b/test/fixtures/typescript/ts/test-cts-typescript.cts @@ -0,0 +1,5 @@ +const str: string = "Hello, TypeScript!"; +interface Foo { + bar: string; +} +console.log(str);