From 7f9ca8d7e2727c19f9b5f129e847c11ebf371160 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 18 Jun 2025 17:52:31 +0000
Subject: [PATCH 1/3] Initial plan for issue
From 55213d837a98a2e8047041af28093ad34c30b461 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 18 Jun 2025 18:05:12 +0000
Subject: [PATCH 2/3] Initial analysis: identified bug in import fixing logic
for symbols in computed property access
Co-authored-by: RyanCavanaugh <6685088+RyanCavanaugh@users.noreply.github.com>
---
.../completionsSymbolTypeOnlyImportBug.ts | 47 +++++++++++++++++++
1 file changed, 47 insertions(+)
create mode 100644 tests/cases/fourslash/completionsSymbolTypeOnlyImportBug.ts
diff --git a/tests/cases/fourslash/completionsSymbolTypeOnlyImportBug.ts b/tests/cases/fourslash/completionsSymbolTypeOnlyImportBug.ts
new file mode 100644
index 0000000000000..1dbaa50dc626d
--- /dev/null
+++ b/tests/cases/fourslash/completionsSymbolTypeOnlyImportBug.ts
@@ -0,0 +1,47 @@
+///
+
+// Test case for symbol property auto-import issue
+// Should import symbol as value, not type when there's already a type-only import
+
+// @Filename: /exportsSymbol.ts
+////export const SYM_FOO_BAR = Symbol.for("foo.bar");
+////
+////export interface ObjWithSym {
+//// [SYM_FOO_BAR]: any;
+////}
+
+// @Filename: /usesSymbol.ts
+////import type { ObjWithSym } from "./exportsSymbol";
+////
+////export declare const thing: ObjWithSym;
+////
+////function main() {
+//// thing[|SYM_FOO_BAR/**/|]
+////}
+
+verify.completions({
+ marker: "",
+ exact: [
+ { name: "SYM_FOO_BAR", source: "/exportsSymbol", insertText: "SYM_FOO_BAR", hasAction: true },
+ ],
+ preferences: {
+ includeInsertTextCompletions: true,
+ includeCompletionsForModuleExports: true,
+ },
+});
+
+// This should create a separate value import, not add to the existing type-only import
+verify.applyCodeActionFromCompletion("", {
+ name: "SYM_FOO_BAR",
+ source: "/exportsSymbol",
+ description: `Add import from "./exportsSymbol"`,
+ newFileContent:
+`import type { ObjWithSym } from "./exportsSymbol";
+import { SYM_FOO_BAR } from "./exportsSymbol";
+
+export declare const thing: ObjWithSym;
+
+function main() {
+ thing[SYM_FOO_BAR]
+}`
+});
\ No newline at end of file
From 56895aab9814ffc43a11c22012cb429637d7ce30 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 18 Jun 2025 18:14:08 +0000
Subject: [PATCH 3/3] Fix symbol auto-import bug: prevent value symbols from
being added to type-only imports
Co-authored-by: RyanCavanaugh <6685088+RyanCavanaugh@users.noreply.github.com>
---
src/services/codefixes/importFixes.ts | 38 +++++++++++--------
.../completionsSymbolTypeOnlyImportBug.ts | 12 +++---
2 files changed, 28 insertions(+), 22 deletions(-)
diff --git a/src/services/codefixes/importFixes.ts b/src/services/codefixes/importFixes.ts
index 6034c9dfc3de1..e04b2b0f5250a 100644
--- a/src/services/codefixes/importFixes.ts
+++ b/src/services/codefixes/importFixes.ts
@@ -1098,22 +1098,28 @@ function getAddAsTypeOnly(
return AddAsTypeOnly.Allowed;
}
-function tryAddToExistingImport(existingImports: readonly FixAddToExistingImportInfo[], isValidTypeOnlyUseSite: boolean, checker: TypeChecker, compilerOptions: CompilerOptions): FixAddToExistingImport | undefined {
- let best: FixAddToExistingImport | undefined;
- for (const existingImport of existingImports) {
- const fix = getAddToExistingImportFix(existingImport);
- if (!fix) continue;
- const isTypeOnly = isTypeOnlyImportDeclaration(fix.importClauseOrBindingPattern);
- if (
- fix.addAsTypeOnly !== AddAsTypeOnly.NotAllowed && isTypeOnly ||
- fix.addAsTypeOnly === AddAsTypeOnly.NotAllowed && !isTypeOnly
- ) {
- // Give preference to putting types in existing type-only imports and avoiding conversions
- // of import statements to/from type-only.
- return fix;
- }
- best ??= fix;
- }
+function tryAddToExistingImport(existingImports: readonly FixAddToExistingImportInfo[], isValidTypeOnlyUseSite: boolean, checker: TypeChecker, compilerOptions: CompilerOptions): FixAddToExistingImport | undefined {
+ let best: FixAddToExistingImport | undefined;
+ for (const existingImport of existingImports) {
+ const fix = getAddToExistingImportFix(existingImport);
+ if (!fix) continue;
+ const isTypeOnly = isTypeOnlyImportDeclaration(fix.importClauseOrBindingPattern);
+
+ // Don't add value-only symbols to type-only imports
+ if (fix.addAsTypeOnly === AddAsTypeOnly.NotAllowed && isTypeOnly) {
+ continue;
+ }
+
+ if (
+ fix.addAsTypeOnly !== AddAsTypeOnly.NotAllowed && isTypeOnly ||
+ fix.addAsTypeOnly === AddAsTypeOnly.NotAllowed && !isTypeOnly
+ ) {
+ // Give preference to putting types in existing type-only imports and avoiding conversions
+ // of import statements to/from type-only.
+ return fix;
+ }
+ best ??= fix;
+ }
return best;
function getAddToExistingImportFix({ declaration, importKind, symbol, targetFlags }: FixAddToExistingImportInfo): FixAddToExistingImport | undefined {
diff --git a/tests/cases/fourslash/completionsSymbolTypeOnlyImportBug.ts b/tests/cases/fourslash/completionsSymbolTypeOnlyImportBug.ts
index 1dbaa50dc626d..b4e175776c889 100644
--- a/tests/cases/fourslash/completionsSymbolTypeOnlyImportBug.ts
+++ b/tests/cases/fourslash/completionsSymbolTypeOnlyImportBug.ts
@@ -1,7 +1,7 @@
///
// Test case for symbol property auto-import issue
-// Should import symbol as value, not type when there's already a type-only import
+// Should import symbol as value, not add to existing type-only import
// @Filename: /exportsSymbol.ts
////export const SYM_FOO_BAR = Symbol.for("foo.bar");
@@ -16,16 +16,16 @@
////export declare const thing: ObjWithSym;
////
////function main() {
-//// thing[|SYM_FOO_BAR/**/|]
+//// thing[/**/]
////}
+goTo.marker("");
+
verify.completions({
- marker: "",
- exact: [
- { name: "SYM_FOO_BAR", source: "/exportsSymbol", insertText: "SYM_FOO_BAR", hasAction: true },
+ includes: [
+ { name: "SYM_FOO_BAR", source: "/exportsSymbol", hasAction: true },
],
preferences: {
- includeInsertTextCompletions: true,
includeCompletionsForModuleExports: true,
},
});