diff --git a/src/compiler/moduleSpecifiers.ts b/src/compiler/moduleSpecifiers.ts
index 7b3ab92f60b04..7da8fba65d3a2 100644
--- a/src/compiler/moduleSpecifiers.ts
+++ b/src/compiler/moduleSpecifiers.ts
@@ -147,7 +147,9 @@ function getPreferences(
return [ModuleSpecifierEnding.JsExtension];
}
if (getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.Classic) {
- return [ModuleSpecifierEnding.Index, ModuleSpecifierEnding.JsExtension];
+ return preferredEnding === ModuleSpecifierEnding.JsExtension
+ ? [ModuleSpecifierEnding.JsExtension, ModuleSpecifierEnding.Index]
+ : [ModuleSpecifierEnding.Index, ModuleSpecifierEnding.JsExtension];
}
switch (preferredEnding) {
case ModuleSpecifierEnding.JsExtension: return [ModuleSpecifierEnding.JsExtension, ModuleSpecifierEnding.Minimal, ModuleSpecifierEnding.Index];
diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts
index bf657d5a15dba..74d9e485e3afb 100644
--- a/src/compiler/utilities.ts
+++ b/src/compiler/utilities.ts
@@ -9094,6 +9094,8 @@ const allSupportedExtensionsWithJson: readonly Extension[][] = [...allSupportedE
export const supportedDeclarationExtensions: readonly Extension[] = [Extension.Dts, Extension.Dcts, Extension.Dmts];
/** @internal */
export const supportedTSImplementationExtensions: readonly Extension[] = [Extension.Ts, Extension.Cts, Extension.Mts, Extension.Tsx];
+/** @internal */
+export const extensionsNotSupportingExtensionlessResolution: readonly Extension[] = [Extension.Mts, Extension.Dmts, Extension.Mjs, Extension.Cts, Extension.Dcts, Extension.Cjs];
/** @internal */
export function getSupportedExtensions(options?: CompilerOptions): readonly Extension[][];
@@ -9156,7 +9158,9 @@ export const enum ModuleSpecifierEnding {
/** @internal */
export function usesExtensionsOnImports({ imports }: SourceFile, hasExtension: (text: string) => boolean = or(hasJSFileExtension, hasTSFileExtension)): boolean {
- return firstDefined(imports, ({ text }) => pathIsRelative(text) ? hasExtension(text) : undefined) || false;
+ return firstDefined(imports, ({ text }) => pathIsRelative(text) && !fileExtensionIsOneOf(text, extensionsNotSupportingExtensionlessResolution)
+ ? hasExtension(text)
+ : undefined) || false;
}
/** @internal */
@@ -9197,6 +9201,10 @@ export function getModuleSpecifierEndingPreference(preference: UserPreferences["
emptyArray;
for (const specifier of specifiers) {
if (pathIsRelative(specifier)) {
+ if (fileExtensionIsOneOf(specifier, extensionsNotSupportingExtensionlessResolution)) {
+ // These extensions are not optional, so do not indicate a preference.
+ continue;
+ }
if (hasTSFileExtension(specifier)) {
return ModuleSpecifierEnding.TsExtension;
}
diff --git a/tests/cases/fourslash/importNameCodeFixInferEndingPreference.ts b/tests/cases/fourslash/importNameCodeFixInferEndingPreference.ts
new file mode 100644
index 0000000000000..6047a6a769fcc
--- /dev/null
+++ b/tests/cases/fourslash/importNameCodeFixInferEndingPreference.ts
@@ -0,0 +1,21 @@
+///
+
+// @module: esnext
+// @moduleResolution: bundler
+
+// @Filename: /a.mts
+//// export {};
+
+// @Filename: /b.ts
+//// export {};
+
+// @Filename: /c.ts
+//// export const c = 0;
+
+// @Filename: /main.ts
+//// import {} from "./a.mjs";
+//// import {} from "./b";
+////
+//// c/**/;
+
+verify.importFixModuleSpecifiers("", ["./c"]);
diff --git a/tests/cases/fourslash/importNameCodeFixInferEndingPreference_classic.ts b/tests/cases/fourslash/importNameCodeFixInferEndingPreference_classic.ts
new file mode 100644
index 0000000000000..08c57e42fd1ea
--- /dev/null
+++ b/tests/cases/fourslash/importNameCodeFixInferEndingPreference_classic.ts
@@ -0,0 +1,19 @@
+///
+
+// @module: esnext
+// @checkJs: true
+// @allowJs: true
+// @noEmit: true
+
+// @Filename: /a.js
+//// export const a = 0;
+
+// @Filename: /b.js
+//// export const b = 0;
+
+// @Filename: /c.js
+//// import { a } from "./a.js";
+////
+//// b/**/;
+
+verify.importFixModuleSpecifiers("", ["./b.js"]);