Skip to content

Commit 48e812a

Browse files
authored
Prefer top-level type-only imports in verbatimModuleSyntax (#52747)
1 parent ab40f5e commit 48e812a

File tree

2 files changed

+60
-4
lines changed

2 files changed

+60
-4
lines changed

src/services/codefixes/importFixes.ts

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -372,7 +372,8 @@ function createImportAdderWorker(sourceFile: SourceFile, program: Program, useAu
372372
quotePreference,
373373
defaultImport,
374374
namedImports && arrayFrom(namedImports.entries(), ([name, addAsTypeOnly]) => ({ addAsTypeOnly, name })),
375-
namespaceLikeImport);
375+
namespaceLikeImport,
376+
compilerOptions);
376377
newDeclarations = combine(newDeclarations, declarations);
377378
});
378379
if (newDeclarations) {
@@ -1249,7 +1250,13 @@ function codeActionForFixWorker(changes: textChanges.ChangeTracker, sourceFile:
12491250
const namespaceLikeImport = importKind === ImportKind.Namespace || importKind === ImportKind.CommonJS
12501251
? { importKind, name: qualification?.namespacePrefix || symbolName, addAsTypeOnly }
12511252
: undefined;
1252-
insertImports(changes, sourceFile, getDeclarations(moduleSpecifier, quotePreference, defaultImport, namedImports, namespaceLikeImport), /*blankLineBetween*/ true, preferences);
1253+
insertImports(changes, sourceFile, getDeclarations(
1254+
moduleSpecifier,
1255+
quotePreference,
1256+
defaultImport,
1257+
namedImports,
1258+
namespaceLikeImport,
1259+
compilerOptions), /*blankLineBetween*/ true, preferences);
12531260
if (qualification) {
12541261
addNamespaceQualifier(changes, sourceFile, qualification);
12551262
}
@@ -1489,12 +1496,18 @@ function getNewImports(
14891496
quotePreference: QuotePreference,
14901497
defaultImport: Import | undefined,
14911498
namedImports: readonly Import[] | undefined,
1492-
namespaceLikeImport: Import & { importKind: ImportKind.CommonJS | ImportKind.Namespace } | undefined
1499+
namespaceLikeImport: Import & { importKind: ImportKind.CommonJS | ImportKind.Namespace } | undefined,
1500+
compilerOptions: CompilerOptions,
14931501
): AnyImportSyntax | readonly AnyImportSyntax[] {
14941502
const quotedModuleSpecifier = makeStringLiteral(moduleSpecifier, quotePreference);
14951503
let statements: AnyImportSyntax | readonly AnyImportSyntax[] | undefined;
14961504
if (defaultImport !== undefined || namedImports?.length) {
1497-
const topLevelTypeOnly = (!defaultImport || needsTypeOnly(defaultImport)) && every(namedImports, needsTypeOnly);
1505+
// `verbatimModuleSyntax` should prefer top-level `import type` -
1506+
// even though it's not an error, it would add unnecessary runtime emit.
1507+
const topLevelTypeOnly = (!defaultImport || needsTypeOnly(defaultImport)) && every(namedImports, needsTypeOnly) ||
1508+
compilerOptions.verbatimModuleSyntax &&
1509+
defaultImport?.addAsTypeOnly !== AddAsTypeOnly.NotAllowed &&
1510+
!some(namedImports, i => i.addAsTypeOnly === AddAsTypeOnly.NotAllowed);
14981511
statements = combine(statements, makeImport(
14991512
defaultImport && factory.createIdentifier(defaultImport.name),
15001513
namedImports?.map(({ addAsTypeOnly, name }) => factory.createImportSpecifier(
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
// @verbatimModuleSyntax: true
4+
// @module: esnext
5+
// @moduleResolution: bundler
6+
7+
// @Filename: /ts.d.ts
8+
//// declare namespace ts {
9+
//// interface SourceFile {
10+
//// text: string;
11+
//// }
12+
//// function createSourceFile(): SourceFile;
13+
//// }
14+
//// export = ts;
15+
16+
// @Filename: /types.ts
17+
//// export interface VFS {
18+
//// getSourceFile(path: string): ts/**/
19+
//// }
20+
21+
verify.completions({
22+
marker: "",
23+
includes: [{
24+
name: "ts",
25+
source: "./ts",
26+
sourceDisplay: "./ts",
27+
hasAction: true,
28+
sortText: completion.SortText.AutoImportSuggestions,
29+
}],
30+
preferences: {
31+
includeCompletionsForModuleExports: true,
32+
allowIncompleteCompletions: true,
33+
},
34+
}).andApplyCodeAction({
35+
name: "ts",
36+
source: "./ts",
37+
description: `Add import from "./ts"`,
38+
newFileContent: `import type ts from "./ts";
39+
40+
export interface VFS {
41+
getSourceFile(path: string): ts
42+
}`
43+
});

0 commit comments

Comments
 (0)