diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts
index 81b188e1a8ed5..869e4a032936e 100644
--- a/src/compiler/binder.ts
+++ b/src/compiler/binder.ts
@@ -517,8 +517,13 @@ namespace ts {
                             }
                         }
 
-                        const declarationName = getNameOfDeclaration(node) || node;
                         const relatedInformation: DiagnosticRelatedInformation[] = [];
+                        if (isTypeAliasDeclaration(node) && nodeIsMissing(node.type) && hasModifier(node, ModifierFlags.Export) && symbol.flags & (SymbolFlags.Alias | SymbolFlags.Type | SymbolFlags.Namespace)) {
+                            // export type T; - may have meant export type { T }?
+                            relatedInformation.push(createDiagnosticForNode(node, Diagnostics.Did_you_mean_0, `export type { ${unescapeLeadingUnderscores(node.name.escapedText)} }`));
+                        }
+
+                        const declarationName = getNameOfDeclaration(node) || node;
                         forEach(symbol.declarations, (declaration, index) => {
                             const decl = getNameOfDeclaration(declaration) || declaration;
                             const diag = createDiagnosticForNode(decl, message, messageNeedsName ? getDisplayName(declaration) : undefined);
@@ -531,7 +536,7 @@ namespace ts {
                         });
 
                         const diag = createDiagnosticForNode(declarationName, message, messageNeedsName ? getDisplayName(node) : undefined);
-                        file.bindDiagnostics.push(multipleDefaultExports ? addRelatedInfo(diag, ...relatedInformation) : diag);
+                        file.bindDiagnostics.push(addRelatedInfo(diag, ...relatedInformation));
 
                         symbol = createSymbol(SymbolFlags.None, name);
                     }
diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts
index 7df196699f8fe..27c4def26f914 100644
--- a/src/compiler/checker.ts
+++ b/src/compiler/checker.ts
@@ -989,10 +989,6 @@ namespace ts {
             return symbol;
         }
 
-        function isTransientSymbol(symbol: Symbol): symbol is TransientSymbol {
-            return (symbol.flags & SymbolFlags.Transient) !== 0;
-        }
-
         function getExcludedSymbolFlags(flags: SymbolFlags): SymbolFlags {
             let result: SymbolFlags = 0;
             if (flags & SymbolFlags.BlockScopedVariable) result |= SymbolFlags.BlockScopedVariableExcludes;
@@ -2047,7 +2043,12 @@ namespace ts {
             if (meaning & (SymbolFlags.Value & ~SymbolFlags.NamespaceModule & ~SymbolFlags.Type)) {
                 const symbol = resolveSymbol(resolveName(errorLocation, name, SymbolFlags.NamespaceModule & ~SymbolFlags.Value, /*nameNotFoundMessage*/undefined, /*nameArg*/ undefined, /*isUse*/ false));
                 if (symbol) {
-                    error(errorLocation, Diagnostics.Cannot_use_namespace_0_as_a_value, unescapeLeadingUnderscores(name));
+                    error(
+                        errorLocation,
+                        isTypeOnlyEnumAlias(symbol)
+                            ? Diagnostics.Enum_0_cannot_be_used_as_a_value_because_only_its_type_has_been_imported
+                            : Diagnostics.Cannot_use_namespace_0_as_a_value,
+                        unescapeLeadingUnderscores(name));
                     return true;
                 }
             }
@@ -2221,15 +2222,25 @@ namespace ts {
                 }
                 else if (hasSyntheticDefault) {
                     // per emit behavior, a synthetic default overrides a "real" .default member if `__esModule` is not present
-                    return resolveExternalModuleSymbol(moduleSymbol, dontResolveAlias) || resolveSymbol(moduleSymbol, dontResolveAlias);
+                    return maybeTypeOnly(
+                        resolveExternalModuleSymbol(moduleSymbol, dontResolveAlias) ||
+                        resolveSymbol(moduleSymbol, dontResolveAlias));
+                }
+                return maybeTypeOnly(exportDefaultSymbol);
+            }
+
+            function maybeTypeOnly(symbol: Symbol | undefined) {
+                if (symbol && node.isTypeOnly && node.name) {
+                    return createTypeOnlyImportOrExport(node.name, symbol);
                 }
-                return exportDefaultSymbol;
+                return symbol;
             }
         }
 
         function getTargetOfNamespaceImport(node: NamespaceImport, dontResolveAlias: boolean): Symbol | undefined {
             const moduleSpecifier = node.parent.parent.moduleSpecifier;
-            return resolveESModuleSymbol(resolveExternalModuleName(node, moduleSpecifier), moduleSpecifier, dontResolveAlias, /*suppressUsageError*/ false);
+            const moduleSymbol = resolveESModuleSymbol(resolveExternalModuleName(node, moduleSpecifier), moduleSpecifier, dontResolveAlias, /*suppressUsageError*/ false);
+            return moduleSymbol && node.parent.isTypeOnly ? createTypeOnlySymbol(moduleSymbol) : moduleSymbol;
         }
 
         function getTargetOfNamespaceExport(node: NamespaceExport, dontResolveAlias: boolean): Symbol | undefined {
@@ -2348,17 +2359,98 @@ namespace ts {
         }
 
         function getTargetOfImportSpecifier(node: ImportSpecifier, dontResolveAlias: boolean): Symbol | undefined {
-            return getExternalModuleMember(node.parent.parent.parent, node, dontResolveAlias);
+            const resolved = getExternalModuleMember(node.parent.parent.parent, node, dontResolveAlias);
+            if (resolved && node.parent.parent.isTypeOnly) {
+                return createTypeOnlyImportOrExport(node.name, resolved);
+            }
+            return resolved;
         }
 
         function getTargetOfNamespaceExportDeclaration(node: NamespaceExportDeclaration, dontResolveAlias: boolean): Symbol {
             return resolveExternalModuleSymbol(node.parent.symbol, dontResolveAlias);
         }
 
+        /**
+         * Creates a type alias symbol with a target symbol for type-only imports and exports.
+         * The symbol for `A` in `export type { A }` or `export type { A } from "./mod"` has
+         * `TypeFlags.Alias` so that alias resolution works as usual, but once the target `A`
+         * has been resolved, we essentially want to pretend we have a type alias to that target.
+         */
+        function createTypeOnlyImportOrExport(sourceNode: ExportSpecifier | Identifier, target: Symbol) {
+            const symbol = createTypeOnlySymbol(target);
+            if (!symbol && target !== unknownSymbol) {
+                const identifier = isExportSpecifier(sourceNode) ? sourceNode.name : sourceNode;
+                const nameText = idText(identifier);
+                const diagnostic = error(
+                    identifier,
+                    Diagnostics.Type_only_0_must_reference_a_type_but_1_is_a_value,
+                    isExportSpecifier(sourceNode) ? "export" : "import",
+                    nameText);
+                const targetDeclaration = target.valueDeclaration ?? target.declarations?.[0];
+                if (targetDeclaration) {
+                    addRelatedInfo(diagnostic, createDiagnosticForNode(
+                        targetDeclaration,
+                        Diagnostics._0_is_declared_here,
+                        nameText));
+                }
+            }
+
+            return symbol;
+        }
+
+        function createTypeOnlySymbol(target: Symbol): Symbol | undefined {
+            if (target.flags & SymbolFlags.ValueModule) {
+                return createNamespaceModuleForModule(target);
+            }
+            if (target.flags & SymbolFlags.Enum) {
+                return createNamespaceModuleForEnum(target);
+            }
+            if (!(target.flags & SymbolFlags.Value)) {
+                return target;
+            }
+            if (target.flags & SymbolFlags.Type) {
+                const alias = createSymbol(SymbolFlags.TypeAlias, target.escapedName);
+                alias.declarations = emptyArray;
+                alias.immediateTarget = target;
+                return alias;
+            }
+        }
+
+        function createNamespaceModuleForEnum(enumSymbol: Symbol) {
+            Debug.assert(!!(enumSymbol.flags & SymbolFlags.Enum));
+            const symbol = createSymbol(SymbolFlags.NamespaceModule | SymbolFlags.TypeAlias, enumSymbol.escapedName);
+            symbol.immediateTarget = enumSymbol;
+            symbol.declarations = enumSymbol.declarations;
+            if (enumSymbol.exports) {
+                symbol.exports = createSymbolTable();
+                enumSymbol.exports.forEach((exportSymbol, key) => {
+                    symbol.exports!.set(key, Debug.assertDefined(createTypeOnlySymbol(exportSymbol)));
+                });
+            }
+            return symbol;
+        }
+
+        function createNamespaceModuleForModule(moduleSymbol: Symbol) {
+            Debug.assert(!!(moduleSymbol.flags & SymbolFlags.ValueModule));
+            const filtered = createSymbol(SymbolFlags.NamespaceModule, moduleSymbol.escapedName);
+            filtered.declarations = moduleSymbol.declarations;
+            if (moduleSymbol.exports) {
+                filtered.exports = createSymbolTable();
+                moduleSymbol.exports.forEach((exportSymbol, key) => {
+                    const typeOnlyExport = createTypeOnlySymbol(exportSymbol);
+                    if (typeOnlyExport) {
+                        filtered.exports!.set(key, typeOnlyExport);
+                    }
+                });
+            }
+            return filtered;
+        }
+
         function getTargetOfExportSpecifier(node: ExportSpecifier, meaning: SymbolFlags, dontResolveAlias?: boolean) {
-            return node.parent.parent.moduleSpecifier ?
+            const target = node.parent.parent.moduleSpecifier ?
                 getExternalModuleMember(node.parent.parent, node, dontResolveAlias) :
                 resolveEntityName(node.propertyName || node.name, meaning, /*ignoreErrors*/ false, dontResolveAlias);
+            return target && node.parent.parent.isTypeOnly ? createTypeOnlyImportOrExport(node, target) : target;
         }
 
         function getTargetOfExportAssignment(node: ExportAssignment | BinaryExpression, dontResolveAlias: boolean): Symbol | undefined {
@@ -8155,13 +8247,20 @@ namespace ts {
                     return errorType;
                 }
 
-                const declaration = find(symbol.declarations, isTypeAlias);
-                if (!declaration) {
-                    return Debug.fail("Type alias symbol with no valid declaration found");
+                let type: Type;
+                let declaration;
+                if (isTypeOnlyAlias(symbol)) {
+                    // Symbol is synthetic type alias for type-only import or export.
+                    // See `createSyntheticTypeAlias`.
+                    type = getDeclaredTypeOfSymbol(symbol.immediateTarget);
+                    declaration = symbol.valueDeclaration;
+                }
+                else {
+                    declaration = Debug.assertDefined(find(symbol.declarations, isTypeAlias), "Type alias symbol with no valid declaration found");
+                    const typeNode = isJSDocTypeAlias(declaration) ? declaration.typeExpression : declaration.type;
+                    // If typeNode is missing, we will error in checkJSDocTypedefTag.
+                    type = typeNode ? getTypeFromTypeNode(typeNode) : errorType;
                 }
-                const typeNode = isJSDocTypeAlias(declaration) ? declaration.typeExpression : declaration.type;
-                // If typeNode is missing, we will error in checkJSDocTypedefTag.
-                let type = typeNode ? getTypeFromTypeNode(typeNode) : errorType;
 
                 if (popTypeResolution()) {
                     const typeParameters = getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol);
@@ -8175,7 +8274,7 @@ namespace ts {
                 }
                 else {
                     type = errorType;
-                    error(isJSDocEnumTag(declaration) ? declaration : declaration.name || declaration, Diagnostics.Type_alias_0_circularly_references_itself, symbolToString(symbol));
+                    error(isNamedDeclaration(declaration) ? declaration.name : declaration || declaration, Diagnostics.Type_alias_0_circularly_references_itself, symbolToString(symbol));
                 }
                 links.declaredType = type;
             }
@@ -10890,6 +10989,9 @@ namespace ts {
             if (symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface)) {
                 return getTypeFromClassOrInterfaceReference(node, symbol);
             }
+            if (isTypeOnlyAlias(symbol)) {
+                return getTypeReferenceType(node, symbol.immediateTarget);
+            }
             if (symbol.flags & SymbolFlags.TypeAlias) {
                 return getTypeFromTypeAliasReference(node, symbol);
             }
@@ -32941,9 +33043,10 @@ namespace ts {
                 // Don't allow to re-export something with no value side when `--isolatedModules` is set.
                 if (compilerOptions.isolatedModules
                     && node.kind === SyntaxKind.ExportSpecifier
+                    && !node.parent.parent.isTypeOnly
                     && !(target.flags & SymbolFlags.Value)
                     && !(node.flags & NodeFlags.Ambient)) {
-                    error(node, Diagnostics.Cannot_re_export_a_type_when_the_isolatedModules_flag_is_provided);
+                    error(node, Diagnostics.Re_exporting_a_type_when_the_isolatedModules_flag_is_provided_requires_using_export_type);
                 }
             }
         }
@@ -32964,7 +33067,7 @@ namespace ts {
             }
             if (checkExternalImportOrExportDeclaration(node)) {
                 const importClause = node.importClause;
-                if (importClause) {
+                if (importClause && !checkGrammarImportClause(importClause)) {
                     if (importClause.name) {
                         checkImportBinding(importClause);
                     }
@@ -33069,6 +33172,40 @@ namespace ts {
             return !isInAppropriateContext;
         }
 
+        function importClauseContainsReferencedImport(importClause: ImportClause) {
+            return importClause.name && isReferenced(importClause)
+                || importClause.namedBindings && namedBindingsContainsReferencedImport(importClause.namedBindings);
+
+            function isReferenced(declaration: Declaration) {
+                return !!getMergedSymbol(getSymbolOfNode(declaration)).isReferenced;
+            }
+            function namedBindingsContainsReferencedImport(namedBindings: NamedImportBindings) {
+                return isNamespaceImport(namedBindings)
+                    ? isReferenced(namedBindings)
+                    : some(namedBindings.elements, isReferenced);
+            }
+        }
+
+        function checkImportsForTypeOnlyConversion(sourceFile: SourceFile) {
+            for (const statement of sourceFile.statements) {
+                if (
+                    isImportDeclaration(statement) &&
+                    statement.importClause &&
+                    !statement.importClause.isTypeOnly &&
+                    importClauseContainsReferencedImport(statement.importClause) &&
+                    !isReferencedAliasDeclaration(statement.importClause, /*checkChildren*/ true)
+                ) {
+                    const isError = compilerOptions.importsNotUsedAsValue === ImportsNotUsedAsValue.Error;
+                    errorOrSuggestion(
+                        isError,
+                        statement,
+                        isError
+                            ? Diagnostics.This_import_is_never_used_as_a_value_and_must_use_import_type_because_the_importsNotUsedAsValue_is_set_to_error
+                            : Diagnostics.This_import_may_be_converted_to_a_type_only_import);
+                }
+            }
+        }
+
         function checkExportSpecifier(node: ExportSpecifier) {
             checkAliasSymbol(node);
             if (getEmitDeclarations(compilerOptions)) {
@@ -33561,6 +33698,10 @@ namespace ts {
                     });
                 }
 
+                if (!node.isDeclarationFile && isExternalModule(node)) {
+                    checkImportsForTypeOnlyConversion(node);
+                }
+
                 if (isExternalOrCommonJsModule(node)) {
                     checkExternalModuleExports(node);
                 }
@@ -33743,10 +33884,10 @@ namespace ts {
         function isTypeDeclarationName(name: Node): boolean {
             return name.kind === SyntaxKind.Identifier &&
                 isTypeDeclaration(name.parent) &&
-                (<NamedDeclaration>name.parent).name === name;
+                name.parent.name === name;
         }
 
-        function isTypeDeclaration(node: Node): node is TypeParameterDeclaration | ClassDeclaration | InterfaceDeclaration | TypeAliasDeclaration | EnumDeclaration {
+        function isTypeDeclaration(node: Node): node is TypeParameterDeclaration | ClassDeclaration | InterfaceDeclaration | TypeAliasDeclaration | EnumDeclaration | ImportClause | ImportSpecifier | ExportSpecifier {
             switch (node.kind) {
                 case SyntaxKind.TypeParameter:
                 case SyntaxKind.ClassDeclaration:
@@ -33754,6 +33895,11 @@ namespace ts {
                 case SyntaxKind.TypeAliasDeclaration:
                 case SyntaxKind.EnumDeclaration:
                     return true;
+                case SyntaxKind.ImportClause:
+                    return (node as ImportClause).isTypeOnly;
+                case SyntaxKind.ImportSpecifier:
+                case SyntaxKind.ExportSpecifier:
+                    return (node as ImportSpecifier | ExportSpecifier).parent.parent.isTypeOnly;
                 default:
                     return false;
             }
@@ -34142,7 +34288,10 @@ namespace ts {
 
             if (isDeclarationNameOrImportPropertyName(node)) {
                 const symbol = getSymbolAtLocation(node);
-                return symbol ? getTypeOfSymbol(symbol) : errorType;
+                if (symbol) {
+                    return isTypeOnlyImportOrExportName(node) ? getDeclaredTypeOfSymbol(symbol) : getTypeOfSymbol(symbol);
+                }
+                return errorType;
             }
 
             if (isBindingPattern(node)) {
@@ -36642,6 +36791,13 @@ namespace ts {
             return ambientModulesCache;
         }
 
+        function checkGrammarImportClause(node: ImportClause): boolean {
+            if (node.isTypeOnly && node.name && node.namedBindings) {
+                return grammarErrorOnNode(node, Diagnostics.A_type_only_import_can_specify_a_default_import_or_named_bindings_but_not_both);
+            }
+            return false;
+        }
+
         function checkGrammarImportCallExpression(node: ImportCall): boolean {
             if (moduleKind === ModuleKind.ES2015) {
                 return grammarErrorOnNode(node, Diagnostics.Dynamic_imports_are_only_supported_when_the_module_flag_is_set_to_es2020_esnext_commonjs_amd_system_or_umd);
diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts
index b0b4c69ca1e15..76477a6fede8b 100644
--- a/src/compiler/commandLineParser.ts
+++ b/src/compiler/commandLineParser.ts
@@ -463,6 +463,17 @@ namespace ts {
             category: Diagnostics.Basic_Options,
             description: Diagnostics.Import_emit_helpers_from_tslib
         },
+        {
+            name: "importsNotUsedAsValue",
+            type: createMapFromTemplate({
+                remove: ImportsNotUsedAsValue.Remove,
+                preserve: ImportsNotUsedAsValue.Preserve,
+                error: ImportsNotUsedAsValue.Error
+            }),
+            affectsEmit: true,
+            category: Diagnostics.Advanced_Options,
+            description: Diagnostics.Specify_emit_Slashchecking_behavior_for_imports_that_are_only_used_for_types
+        },
         {
             name: "downlevelIteration",
             type: "boolean",
diff --git a/src/compiler/core.ts b/src/compiler/core.ts
index 203835b49f6a9..cd81020c0f1b7 100644
--- a/src/compiler/core.ts
+++ b/src/compiler/core.ts
@@ -1509,6 +1509,13 @@ namespace ts {
         return compareComparableValues(a, b);
     }
 
+    /**
+     * Compare two TextSpans, first by `start`, then by `length`.
+     */
+    export function compareTextSpans(a: Partial<TextSpan> | undefined, b: Partial<TextSpan> | undefined): Comparison {
+        return compareValues(a?.start, b?.start) || compareValues(a?.length, b?.length);
+    }
+
     export function min<T>(a: T, b: T, compare: Comparer<T>): T {
         return compare(a, b) === Comparison.LessThan ? a : b;
     }
@@ -1914,10 +1921,10 @@ namespace ts {
         return (arg: T) => f(arg) && g(arg);
     }
 
-    export function or<T extends unknown>(...fs: ((arg: T) => boolean)[]): (arg: T) => boolean {
-        return arg => {
+    export function or<T extends unknown[]>(...fs: ((...args: T) => boolean)[]): (...args: T) => boolean {
+        return (...args) => {
             for (const f of fs) {
-                if (f(arg)) {
+                if (f(...args)) {
                     return true;
                 }
             }
diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json
index f7949496bfee2..43683086cde67 100644
--- a/src/compiler/diagnosticMessages.json
+++ b/src/compiler/diagnosticMessages.json
@@ -639,7 +639,7 @@
         "category": "Error",
         "code": 1203
     },
-    "Cannot re-export a type when the '--isolatedModules' flag is provided.": {
+    "Re-exporting a type when the '--isolatedModules' flag is provided requires using 'export type'.": {
         "category": "Error",
         "code": 1205
     },
@@ -1059,10 +1059,66 @@
         "category": "Error",
         "code": 1360
     },
-    "'await' outside of an async function is only allowed at the top level of a module when '--module' is 'esnext' or 'system' and '--target' is 'es2017' or higher.": {
+    "Type-only {0} must reference a type, but '{1}' is a value.": {
         "category": "Error",
         "code": 1361
     },
+    "Enum '{0}' cannot be used as a value because only its type has been imported.": {
+        "category": "Error",
+        "code": 1362
+    },
+    "A type-only import can specify a default import or named bindings, but not both.": {
+        "category": "Error",
+        "code": 1363
+    },
+    "Convert to type-only export": {
+        "category": "Message",
+        "code": 1364
+    },
+    "Convert all re-exported types to type-only exports": {
+        "category": "Message",
+        "code": 1365
+    },
+    "Split into two separate import declarations": {
+        "category": "Message",
+        "code": 1366
+    },
+    "Split all invalid type-only imports": {
+        "category": "Message",
+        "code": 1377
+    },
+    "Specify emit/checking behavior for imports that are only used for types": {
+        "category": "Message",
+        "code": 1368
+    },
+    "Did you mean '{0}'?": {
+        "category": "Message",
+        "code": 1369
+    },
+    "Only ECMAScript imports may use 'import type'.": {
+        "category": "Error",
+        "code": 1370
+    },
+    "This import is never used as a value and must use 'import type' because the 'importsNotUsedAsValue' is set to 'error'.": {
+        "category": "Error",
+        "code": 1371
+    },
+    "This import may be converted to a type-only import.": {
+        "category": "Suggestion",
+        "code": 1372
+    },
+    "Convert to type-only import": {
+        "category": "Message",
+        "code": 1373
+    },
+    "Convert all imports not used as a value to type-only imports": {
+        "category": "Message",
+        "code": 1374
+    },
+    "'await' outside of an async function is only allowed at the top level of a module when '--module' is 'esnext' or 'system' and '--target' is 'es2017' or higher.": {
+        "category": "Error",
+        "code": 1375
+    },
 
     "The types of '{0}' are incompatible between these types.": {
         "category": "Error",
diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts
index 48e35cb1e2550..d576083087102 100644
--- a/src/compiler/emitter.ts
+++ b/src/compiler/emitter.ts
@@ -3048,6 +3048,10 @@ namespace ts {
         }
 
         function emitImportClause(node: ImportClause) {
+            if (node.isTypeOnly) {
+                emitTokenWithComment(SyntaxKind.TypeKeyword, node.pos, writeKeyword, node);
+                writeSpace();
+            }
             emit(node.name);
             if (node.name && node.namedBindings) {
                 emitTokenWithComment(SyntaxKind.CommaToken, node.name.end, writePunctuation, node);
@@ -3089,6 +3093,10 @@ namespace ts {
         function emitExportDeclaration(node: ExportDeclaration) {
             let nextPos = emitTokenWithComment(SyntaxKind.ExportKeyword, node.pos, writeKeyword, node);
             writeSpace();
+            if (node.isTypeOnly) {
+                nextPos = emitTokenWithComment(SyntaxKind.TypeKeyword, nextPos, writeKeyword, node);
+                writeSpace();
+            }
             if (node.exportClause) {
                 emit(node.exportClause);
             }
diff --git a/src/compiler/factoryPublic.ts b/src/compiler/factoryPublic.ts
index 0d9adc26d9cbf..19e927f4f6673 100644
--- a/src/compiler/factoryPublic.ts
+++ b/src/compiler/factoryPublic.ts
@@ -2267,17 +2267,19 @@ namespace ts {
             : node;
     }
 
-    export function createImportClause(name: Identifier | undefined, namedBindings: NamedImportBindings | undefined): ImportClause {
+    export function createImportClause(name: Identifier | undefined, namedBindings: NamedImportBindings | undefined, isTypeOnly = false): ImportClause {
         const node = <ImportClause>createSynthesizedNode(SyntaxKind.ImportClause);
         node.name = name;
         node.namedBindings = namedBindings;
+        node.isTypeOnly = isTypeOnly;
         return node;
     }
 
-    export function updateImportClause(node: ImportClause, name: Identifier | undefined, namedBindings: NamedImportBindings | undefined) {
+    export function updateImportClause(node: ImportClause, name: Identifier | undefined, namedBindings: NamedImportBindings | undefined, isTypeOnly: boolean) {
         return node.name !== name
             || node.namedBindings !== namedBindings
-            ? updateNode(createImportClause(name, namedBindings), node)
+            || node.isTypeOnly !== isTypeOnly
+            ? updateNode(createImportClause(name, namedBindings, isTypeOnly), node)
             : node;
     }
 
@@ -2348,10 +2350,11 @@ namespace ts {
             : node;
     }
 
-    export function createExportDeclaration(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, exportClause: NamedExportBindings | undefined, moduleSpecifier?: Expression) {
+    export function createExportDeclaration(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, exportClause: NamedExportBindings | undefined, moduleSpecifier?: Expression, isTypeOnly = false) {
         const node = <ExportDeclaration>createSynthesizedNode(SyntaxKind.ExportDeclaration);
         node.decorators = asNodeArray(decorators);
         node.modifiers = asNodeArray(modifiers);
+        node.isTypeOnly = isTypeOnly;
         node.exportClause = exportClause;
         node.moduleSpecifier = moduleSpecifier;
         return node;
@@ -2362,12 +2365,14 @@ namespace ts {
         decorators: readonly Decorator[] | undefined,
         modifiers: readonly Modifier[] | undefined,
         exportClause: NamedExportBindings | undefined,
-        moduleSpecifier: Expression | undefined) {
+        moduleSpecifier: Expression | undefined,
+        isTypeOnly: boolean) {
         return node.decorators !== decorators
             || node.modifiers !== modifiers
+            || node.isTypeOnly !== isTypeOnly
             || node.exportClause !== exportClause
             || node.moduleSpecifier !== moduleSpecifier
-            ? updateNode(createExportDeclaration(decorators, modifiers, exportClause, moduleSpecifier), node)
+            ? updateNode(createExportDeclaration(decorators, modifiers, exportClause, moduleSpecifier, isTypeOnly), node)
             : node;
     }
 
diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts
index 2287c41431616..28fc666a8da40 100644
--- a/src/compiler/parser.ts
+++ b/src/compiler/parser.ts
@@ -1516,7 +1516,10 @@ namespace ts {
                     if (token() === SyntaxKind.DefaultKeyword) {
                         return lookAhead(nextTokenCanFollowDefaultKeyword);
                     }
-                    return token() !== SyntaxKind.AsteriskToken && token() !== SyntaxKind.AsKeyword && token() !== SyntaxKind.OpenBraceToken && canFollowModifier();
+                    if (token() === SyntaxKind.TypeKeyword) {
+                        return lookAhead(nextTokenCanFollowExportModifier);
+                    }
+                    return canFollowExportModifier();
                 case SyntaxKind.DefaultKeyword:
                     return nextTokenCanFollowDefaultKeyword();
                 case SyntaxKind.StaticKeyword:
@@ -1529,6 +1532,18 @@ namespace ts {
             }
         }
 
+        function canFollowExportModifier(): boolean {
+            return token() !== SyntaxKind.AsteriskToken
+                && token() !== SyntaxKind.AsKeyword
+                && token() !== SyntaxKind.OpenBraceToken
+                && canFollowModifier();
+        }
+
+        function nextTokenCanFollowExportModifier(): boolean {
+            nextToken();
+            return canFollowExportModifier();
+        }
+
         function parseAnyContextualModifier(): boolean {
             return isModifierKind(token()) && tryParse(nextTokenCanFollowModifier);
         }
@@ -5470,10 +5485,13 @@ namespace ts {
                         return token() === SyntaxKind.StringLiteral || token() === SyntaxKind.AsteriskToken ||
                             token() === SyntaxKind.OpenBraceToken || tokenIsIdentifierOrKeyword(token());
                     case SyntaxKind.ExportKeyword:
-                        nextToken();
-                        if (token() === SyntaxKind.EqualsToken || token() === SyntaxKind.AsteriskToken ||
-                            token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.DefaultKeyword ||
-                            token() === SyntaxKind.AsKeyword) {
+                        let currentToken = nextToken();
+                        if (currentToken === SyntaxKind.TypeKeyword) {
+                            currentToken = lookAhead(nextToken);
+                        }
+                        if (currentToken === SyntaxKind.EqualsToken || currentToken === SyntaxKind.AsteriskToken ||
+                            currentToken === SyntaxKind.OpenBraceToken || currentToken === SyntaxKind.DefaultKeyword ||
+                            currentToken === SyntaxKind.AsKeyword) {
                             return true;
                         }
                         continue;
@@ -6355,9 +6373,19 @@ namespace ts {
             let identifier: Identifier | undefined;
             if (isIdentifier()) {
                 identifier = parseIdentifier();
-                if (token() !== SyntaxKind.CommaToken && token() !== SyntaxKind.FromKeyword) {
-                    return parseImportEqualsDeclaration(<ImportEqualsDeclaration>node, identifier);
-                }
+            }
+
+            let isTypeOnly = false;
+            if (token() !== SyntaxKind.FromKeyword &&
+                identifier?.escapedText === "type" &&
+                (isIdentifier() || tokenAfterImportDefinitelyProducesImportDeclaration())
+            ) {
+                isTypeOnly = true;
+                identifier = isIdentifier() ? parseIdentifier() : undefined;
+            }
+
+            if (identifier && !tokenAfterImportedIdentifierDefinitelyProducesImportDeclaration()) {
+                return parseImportEqualsDeclaration(<ImportEqualsDeclaration>node, identifier, isTypeOnly);
             }
 
             // Import statement
@@ -6366,9 +6394,10 @@ namespace ts {
             //  import ImportClause from ModuleSpecifier ;
             //  import ModuleSpecifier;
             if (identifier || // import id
-                token() === SyntaxKind.AsteriskToken || // import *
-                token() === SyntaxKind.OpenBraceToken) { // import {
-                (<ImportDeclaration>node).importClause = parseImportClause(identifier, afterImportPos);
+                token() === SyntaxKind.AsteriskToken ||  // import *
+                token() === SyntaxKind.OpenBraceToken    // import {
+            ) {
+                (<ImportDeclaration>node).importClause = parseImportClause(identifier, afterImportPos, isTypeOnly);
                 parseExpected(SyntaxKind.FromKeyword);
             }
 
@@ -6377,16 +6406,30 @@ namespace ts {
             return finishNode(node);
         }
 
-        function parseImportEqualsDeclaration(node: ImportEqualsDeclaration, identifier: Identifier): ImportEqualsDeclaration {
+        function tokenAfterImportDefinitelyProducesImportDeclaration() {
+            return token() === SyntaxKind.AsteriskToken || token() === SyntaxKind.OpenBraceToken;
+        }
+
+        function tokenAfterImportedIdentifierDefinitelyProducesImportDeclaration() {
+            // In `import id ___`, the current token decides whether to produce
+            // an ImportDeclaration or ImportEqualsDeclaration.
+            return token() === SyntaxKind.CommaToken || token() === SyntaxKind.FromKeyword;
+        }
+
+        function parseImportEqualsDeclaration(node: ImportEqualsDeclaration, identifier: Identifier, isTypeOnly: boolean): ImportEqualsDeclaration {
             node.kind = SyntaxKind.ImportEqualsDeclaration;
             node.name = identifier;
             parseExpected(SyntaxKind.EqualsToken);
             node.moduleReference = parseModuleReference();
             parseSemicolon();
-            return finishNode(node);
+            const finished = finishNode(node);
+            if (isTypeOnly) {
+                parseErrorAtRange(finished, Diagnostics.Only_ECMAScript_imports_may_use_import_type);
+            }
+            return finished;
         }
 
-        function parseImportClause(identifier: Identifier | undefined, fullStart: number) {
+        function parseImportClause(identifier: Identifier | undefined, fullStart: number, isTypeOnly: boolean) {
             // ImportClause:
             //  ImportedDefaultBinding
             //  NameSpaceImport
@@ -6395,6 +6438,8 @@ namespace ts {
             //  ImportedDefaultBinding, NamedImports
 
             const importClause = <ImportClause>createNode(SyntaxKind.ImportClause, fullStart);
+            importClause.isTypeOnly = isTypeOnly;
+
             if (identifier) {
                 // ImportedDefaultBinding:
                 //  ImportedBinding
@@ -6514,6 +6559,7 @@ namespace ts {
 
         function parseExportDeclaration(node: ExportDeclaration): ExportDeclaration {
             node.kind = SyntaxKind.ExportDeclaration;
+            node.isTypeOnly = parseOptional(SyntaxKind.TypeKeyword);
             if (parseOptional(SyntaxKind.AsteriskToken)) {
                 if (parseOptional(SyntaxKind.AsKeyword)) {
                     node.exportClause = parseNamespaceExport();
diff --git a/src/compiler/program.ts b/src/compiler/program.ts
index 891763ddbbd33..3a23230b4c382 100644
--- a/src/compiler/program.ts
+++ b/src/compiler/program.ts
@@ -1820,6 +1820,18 @@ namespace ts {
                     }
 
                     switch (node.kind) {
+                        case SyntaxKind.ImportClause:
+                            if ((node as ImportClause).isTypeOnly) {
+                                diagnostics.push(createDiagnosticForNode(node.parent, Diagnostics._0_declarations_can_only_be_used_in_TypeScript_files, "import type"));
+                                return;
+                            }
+                            break;
+                        case SyntaxKind.ExportDeclaration:
+                            if ((node as ExportDeclaration).isTypeOnly) {
+                                diagnostics.push(createDiagnosticForNode(node, Diagnostics._0_declarations_can_only_be_used_in_TypeScript_files, "export type"));
+                                return;
+                            }
+                            break;
                         case SyntaxKind.ImportEqualsDeclaration:
                             diagnostics.push(createDiagnosticForNode(node, Diagnostics.import_can_only_be_used_in_TypeScript_files));
                             return;
diff --git a/src/compiler/transformers/declarations.ts b/src/compiler/transformers/declarations.ts
index 0b81d2bb32043..e2dbe8a2bd34e 100644
--- a/src/compiler/transformers/declarations.ts
+++ b/src/compiler/transformers/declarations.ts
@@ -686,7 +686,8 @@ namespace ts {
                 return visibleDefaultBinding && updateImportDeclaration(decl, /*decorators*/ undefined, decl.modifiers, updateImportClause(
                     decl.importClause,
                     visibleDefaultBinding,
-                    /*namedBindings*/ undefined
+                    /*namedBindings*/ undefined,
+                    decl.importClause.isTypeOnly,
                 ), rewriteModuleSpecifier(decl, decl.moduleSpecifier));
             }
             if (decl.importClause.namedBindings.kind === SyntaxKind.NamespaceImport) {
@@ -695,7 +696,8 @@ namespace ts {
                 return visibleDefaultBinding || namedBindings ? updateImportDeclaration(decl, /*decorators*/ undefined, decl.modifiers, updateImportClause(
                     decl.importClause,
                     visibleDefaultBinding,
-                    namedBindings
+                    namedBindings,
+                    decl.importClause.isTypeOnly,
                 ), rewriteModuleSpecifier(decl, decl.moduleSpecifier)) : undefined;
             }
             // Named imports (optionally with visible default)
@@ -708,7 +710,8 @@ namespace ts {
                     updateImportClause(
                         decl.importClause,
                         visibleDefaultBinding,
-                        bindingList && bindingList.length ? updateNamedImports(decl.importClause.namedBindings, bindingList) : undefined
+                        bindingList && bindingList.length ? updateNamedImports(decl.importClause.namedBindings, bindingList) : undefined,
+                        decl.importClause.isTypeOnly,
                     ),
                     rewriteModuleSpecifier(decl, decl.moduleSpecifier)
                 );
@@ -1033,7 +1036,13 @@ namespace ts {
                     resultHasScopeMarker = true;
                     // Always visible if the parent node isn't dropped for being not visible
                     // Rewrite external module names if necessary
-                    return updateExportDeclaration(input, /*decorators*/ undefined, input.modifiers, input.exportClause, rewriteModuleSpecifier(input, input.moduleSpecifier));
+                    return updateExportDeclaration(
+                        input,
+                        /*decorators*/ undefined,
+                        input.modifiers,
+                        input.exportClause,
+                        rewriteModuleSpecifier(input, input.moduleSpecifier),
+                        input.isTypeOnly);
                 }
                 case SyntaxKind.ExportAssignment: {
                     // Always visible if the parent node isn't dropped for being not visible
diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts
index 3b83356acbfb7..e855981114f37 100644
--- a/src/compiler/transformers/ts.ts
+++ b/src/compiler/transformers/ts.ts
@@ -2760,7 +2760,7 @@ namespace ts {
         }
 
         /**
-         * Visits an import declaration, eliding it if it is not referenced.
+         * Visits an import declaration, eliding it if it is not referenced and `importsNotUsedAsValue` is not 'preserve'.
          *
          * @param node The import declaration node.
          */
@@ -2770,10 +2770,16 @@ namespace ts {
                 //  import "foo";
                 return node;
             }
+            if (node.importClause.isTypeOnly) {
+                // Always elide type-only imports
+                return undefined;
+            }
 
             // Elide the declaration if the import clause was elided.
             const importClause = visitNode(node.importClause, visitImportClause, isImportClause);
-            return importClause
+            return importClause ||
+                compilerOptions.importsNotUsedAsValue === ImportsNotUsedAsValue.Preserve ||
+                compilerOptions.importsNotUsedAsValue === ImportsNotUsedAsValue.Error
                 ? updateImportDeclaration(
                     node,
                     /*decorators*/ undefined,
@@ -2789,10 +2795,13 @@ namespace ts {
          * @param node The import clause node.
          */
         function visitImportClause(node: ImportClause): VisitResult<ImportClause> {
+            if (node.isTypeOnly) {
+                return undefined;
+            }
             // Elide the import clause if we elide both its name and its named bindings.
             const name = resolver.isReferencedAliasDeclaration(node) ? node.name : undefined;
             const namedBindings = visitNode(node.namedBindings, visitNamedImportBindings, isNamedImportBindings);
-            return (name || namedBindings) ? updateImportClause(node, name, namedBindings) : undefined;
+            return (name || namedBindings) ? updateImportClause(node, name, namedBindings, /*isTypeOnly*/ false) : undefined;
         }
 
         /**
@@ -2842,6 +2851,10 @@ namespace ts {
          * @param node The export declaration node.
          */
         function visitExportDeclaration(node: ExportDeclaration): VisitResult<Statement> {
+            if (node.isTypeOnly) {
+                return undefined;
+            }
+
             if (!node.exportClause) {
                 // Elide a star export if the module it references does not export a value.
                 return compilerOptions.isolatedModules || resolver.moduleExportsSomeValue(node.moduleSpecifier!) ? node : undefined;
@@ -2860,7 +2873,8 @@ namespace ts {
                     /*decorators*/ undefined,
                     /*modifiers*/ undefined,
                     exportClause,
-                    node.moduleSpecifier)
+                    node.moduleSpecifier,
+                    node.isTypeOnly)
                 : undefined;
         }
 
@@ -2915,10 +2929,24 @@ namespace ts {
          */
         function visitImportEqualsDeclaration(node: ImportEqualsDeclaration): VisitResult<Statement> {
             if (isExternalModuleImportEqualsDeclaration(node)) {
-                // Elide external module `import=` if it is not referenced.
-                return resolver.isReferencedAliasDeclaration(node)
-                    ? visitEachChild(node, visitor, context)
-                    : undefined;
+                const isReferenced = resolver.isReferencedAliasDeclaration(node);
+                // If the alias is unreferenced but we want to keep the import, replace with 'import "mod"'.
+                if (!isReferenced && compilerOptions.importsNotUsedAsValue === ImportsNotUsedAsValue.Preserve) {
+                    return setOriginalNode(
+                        setTextRange(
+                            createImportDeclaration(
+                                /*decorators*/ undefined,
+                                /*modifiers*/ undefined,
+                                /*importClause*/ undefined,
+                                node.moduleReference.expression,
+                            ),
+                            node,
+                        ),
+                        node,
+                    );
+                }
+
+                return isReferenced ? visitEachChild(node, visitor, context) : undefined;
             }
 
             if (!shouldEmitImportEqualsDeclaration(node)) {
diff --git a/src/compiler/types.ts b/src/compiler/types.ts
index 107f2b8155205..36275107b10f6 100644
--- a/src/compiler/types.ts
+++ b/src/compiler/types.ts
@@ -2477,6 +2477,7 @@ namespace ts {
     export interface ImportClause extends NamedDeclaration {
         kind: SyntaxKind.ImportClause;
         parent: ImportDeclaration;
+        isTypeOnly: boolean;
         name?: Identifier; // Default binding
         namedBindings?: NamedImportBindings;
     }
@@ -2501,6 +2502,7 @@ namespace ts {
     export interface ExportDeclaration extends DeclarationStatement, JSDocContainer {
         kind: SyntaxKind.ExportDeclaration;
         parent: SourceFile | ModuleBlock;
+        isTypeOnly: boolean;
         /** Will not be assigned in the case of `export * from "foo";` */
         exportClause?: NamedExportBindings;
         /** If this is not a StringLiteral it will be a grammar error. */
@@ -5041,6 +5043,7 @@ namespace ts {
         /*@internal*/generateCpuProfile?: string;
         /*@internal*/help?: boolean;
         importHelpers?: boolean;
+        importsNotUsedAsValue?: ImportsNotUsedAsValue;
         /*@internal*/init?: boolean;
         inlineSourceMap?: boolean;
         inlineSources?: boolean;
@@ -5161,6 +5164,12 @@ namespace ts {
         ReactNative = 3
     }
 
+    export const enum ImportsNotUsedAsValue {
+        Remove,
+        Preserve,
+        Error
+    }
+
     export const enum NewLineKind {
         CarriageReturnLineFeed = 0,
         LineFeed = 1
diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts
index 93343650841c7..e8eb00e21f23c 100644
--- a/src/compiler/utilities.ts
+++ b/src/compiler/utilities.ts
@@ -40,6 +40,18 @@ namespace ts {
         return result;
     }
 
+    export function isTransientSymbol(symbol: Symbol): symbol is TransientSymbol {
+        return (symbol.flags & SymbolFlags.Transient) !== 0;
+    }
+
+    export function isTypeOnlyAlias(symbol: Symbol): symbol is TransientSymbol & { immediateTarget: Symbol } {
+        return isTransientSymbol(symbol) && !!symbol.immediateTarget;
+    }
+
+    export function isTypeOnlyEnumAlias(symbol: Symbol): ReturnType<typeof isTypeOnlyAlias> {
+        return isTypeOnlyAlias(symbol) && !!(symbol.immediateTarget.flags & SymbolFlags.Enum);
+    }
+
     const stringWriter = createSingleLineStringWriter();
 
     function createSingleLineStringWriter(): EmitTextWriter {
@@ -1767,7 +1779,7 @@ namespace ts {
         }
     }
 
-    export function isExternalModuleImportEqualsDeclaration(node: Node) {
+    export function isExternalModuleImportEqualsDeclaration(node: Node): node is ImportEqualsDeclaration & { moduleReference: ExternalModuleReference } {
         return node.kind === SyntaxKind.ImportEqualsDeclaration && (<ImportEqualsDeclaration>node).moduleReference.kind === SyntaxKind.ExternalModuleReference;
     }
 
@@ -5879,6 +5891,9 @@ namespace ts {
     }
 
     export function addRelatedInfo<T extends Diagnostic>(diagnostic: T, ...relatedInformation: DiagnosticRelatedInformation[]): T {
+        if (!relatedInformation.length) {
+            return diagnostic;
+        }
         if (!diagnostic.relatedInformation) {
             diagnostic.relatedInformation = [];
         }
diff --git a/src/compiler/utilitiesPublic.ts b/src/compiler/utilitiesPublic.ts
index 1dc3a87742ebe..d4bc403b85908 100644
--- a/src/compiler/utilitiesPublic.ts
+++ b/src/compiler/utilitiesPublic.ts
@@ -1721,6 +1721,21 @@ namespace ts {
         return isImportSpecifier(node) || isExportSpecifier(node);
     }
 
+    export function isTypeOnlyImportOrExportName(node: Node): boolean {
+        if (node.kind !== SyntaxKind.Identifier) {
+            return false;
+        }
+        switch (node.parent.kind) {
+            case SyntaxKind.ImportSpecifier:
+            case SyntaxKind.ExportSpecifier:
+                return (node.parent as ImportSpecifier | ExportSpecifier).parent.parent.isTypeOnly;
+            case SyntaxKind.ImportClause:
+                return (node.parent as ImportClause).isTypeOnly;
+            default:
+                return false;
+        }
+    }
+
     export function isStringTextContainingNode(node: Node): node is StringLiteral | TemplateLiteralToken {
         return node.kind === SyntaxKind.StringLiteral || isTemplateLiteralKind(node.kind);
     }
diff --git a/src/compiler/visitorPublic.ts b/src/compiler/visitorPublic.ts
index 0a40cd473305e..3cbd60ff51614 100644
--- a/src/compiler/visitorPublic.ts
+++ b/src/compiler/visitorPublic.ts
@@ -792,7 +792,8 @@ namespace ts {
             case SyntaxKind.ImportClause:
                 return updateImportClause(<ImportClause>node,
                     visitNode((<ImportClause>node).name, visitor, isIdentifier),
-                    visitNode((<ImportClause>node).namedBindings, visitor, isNamedImportBindings));
+                    visitNode((<ImportClause>node).namedBindings, visitor, isNamedImportBindings),
+                    (node as ImportClause).isTypeOnly);
 
             case SyntaxKind.NamespaceImport:
                 return updateNamespaceImport(<NamespaceImport>node,
@@ -822,7 +823,8 @@ namespace ts {
                     nodesVisitor((<ExportDeclaration>node).decorators, visitor, isDecorator),
                     nodesVisitor((<ExportDeclaration>node).modifiers, visitor, isModifier),
                     visitNode((<ExportDeclaration>node).exportClause, visitor, isNamedExportBindings),
-                    visitNode((<ExportDeclaration>node).moduleSpecifier, visitor, isExpression));
+                    visitNode((<ExportDeclaration>node).moduleSpecifier, visitor, isExpression),
+                    (node as ExportDeclaration).isTypeOnly);
 
             case SyntaxKind.NamedExports:
                 return updateNamedExports(<NamedExports>node,
diff --git a/src/harness/fourslashImpl.ts b/src/harness/fourslashImpl.ts
index 952ba36b7598e..972c191f189f0 100644
--- a/src/harness/fourslashImpl.ts
+++ b/src/harness/fourslashImpl.ts
@@ -738,7 +738,15 @@ namespace FourSlash {
             }
 
             if (!range) {
-                this.raiseError(`goToDefinitionsAndBoundSpan failed - found a TextSpan ${JSON.stringify(defs.textSpan)} when it wasn't expected.`);
+                const marker = this.getMarkerByName(startMarkerName);
+                const startFile = marker.fileName;
+                const fileContent = this.getFileContent(startFile);
+                const spanContent = fileContent.slice(defs.textSpan.start, ts.textSpanEnd(defs.textSpan));
+                const spanContentWithMarker = spanContent.slice(0, marker.position - defs.textSpan.start) + `/*${startMarkerName}*/` + spanContent.slice(marker.position - defs.textSpan.start);
+                const suggestedFileContent = (fileContent.slice(0, defs.textSpan.start) + `\x1b[1;4m[|${spanContentWithMarker}|]\x1b[31m` + fileContent.slice(ts.textSpanEnd(defs.textSpan)))
+                    .split(/\r?\n/).map(line => " ".repeat(6) + line).join(ts.sys.newLine);
+                this.raiseError(`goToDefinitionsAndBoundSpan failed. Found a starting TextSpan around '${spanContent}' in '${startFile}' (at position ${defs.textSpan.start}). `
+                    + `If this is the correct input span, put a fourslash range around it: \n\n${suggestedFileContent}\n`);
             }
             else {
                 this.assertTextSpanEqualsRange(defs.textSpan, range, "goToDefinitionsAndBoundSpan failed");
diff --git a/src/services/codefixes/convertToTypeOnlyExport.ts b/src/services/codefixes/convertToTypeOnlyExport.ts
new file mode 100644
index 0000000000000..7adf4d1aacd67
--- /dev/null
+++ b/src/services/codefixes/convertToTypeOnlyExport.ts
@@ -0,0 +1,83 @@
+/* @internal */
+namespace ts.codefix {
+    const errorCodes = [Diagnostics.Re_exporting_a_type_when_the_isolatedModules_flag_is_provided_requires_using_export_type.code];
+    const fixId = "convertToTypeOnlyExport";
+    registerCodeFix({
+        errorCodes,
+        getCodeActions: context => {
+            const changes = textChanges.ChangeTracker.with(context, t => fixSingleExportDeclaration(t, getExportSpecifierForDiagnosticSpan(context.span, context.sourceFile), context));
+            if (changes.length) {
+                return [createCodeFixAction(fixId, changes, Diagnostics.Convert_to_type_only_export, fixId, Diagnostics.Convert_all_re_exported_types_to_type_only_exports)];
+            }
+        },
+        fixIds: [fixId],
+        getAllCodeActions: context => {
+            const fixedExportDeclarations = createMap<true>();
+            return codeFixAll(context, errorCodes, (changes, diag) => {
+                const exportSpecifier = getExportSpecifierForDiagnosticSpan(diag, context.sourceFile);
+                if (exportSpecifier && !addToSeen(fixedExportDeclarations, getNodeId(exportSpecifier.parent.parent))) {
+                    fixSingleExportDeclaration(changes, exportSpecifier, context);
+                }
+            });
+        }
+    });
+
+    function getExportSpecifierForDiagnosticSpan(span: TextSpan, sourceFile: SourceFile) {
+        return tryCast(getTokenAtPosition(sourceFile, span.start).parent, isExportSpecifier);
+    }
+
+    function fixSingleExportDeclaration(changes: textChanges.ChangeTracker, exportSpecifier: ExportSpecifier | undefined, context: CodeFixContextBase) {
+        if (!exportSpecifier) {
+            return;
+        }
+
+        const exportClause = exportSpecifier.parent;
+        const exportDeclaration = exportClause.parent;
+        const typeExportSpecifiers = getTypeExportSpecifiers(exportSpecifier, context);
+        if (typeExportSpecifiers.length === exportClause.elements.length) {
+            changes.replaceNode(
+                context.sourceFile,
+                exportDeclaration,
+                updateExportDeclaration(
+                    exportDeclaration,
+                    exportDeclaration.decorators,
+                    exportDeclaration.modifiers,
+                    exportClause,
+                    exportDeclaration.moduleSpecifier,
+                    /*isTypeOnly*/ true));
+        }
+        else {
+            const valueExportDeclaration = updateExportDeclaration(
+                exportDeclaration,
+                exportDeclaration.decorators,
+                exportDeclaration.modifiers,
+                updateNamedExports(exportClause, filter(exportClause.elements, e => !contains(typeExportSpecifiers, e))),
+                exportDeclaration.moduleSpecifier,
+                /*isTypeOnly*/ false);
+            const typeExportDeclaration = createExportDeclaration(
+                /*decorators*/ undefined,
+                /*modifiers*/ undefined,
+                createNamedExports(typeExportSpecifiers),
+                exportDeclaration.moduleSpecifier,
+                /*isTypeOnly*/ true);
+
+            changes.replaceNode(context.sourceFile, exportDeclaration, valueExportDeclaration);
+            changes.insertNodeAfter(context.sourceFile, exportDeclaration, typeExportDeclaration);
+        }
+    }
+
+    function getTypeExportSpecifiers(originExportSpecifier: ExportSpecifier, context: CodeFixContextBase): readonly ExportSpecifier[] {
+        const exportClause = originExportSpecifier.parent;
+        if (exportClause.elements.length === 1) {
+            return exportClause.elements;
+        }
+
+        const diagnostics = getDiagnosticsWithinSpan(
+            createTextSpanFromNode(exportClause),
+            context.program.getSemanticDiagnostics(context.sourceFile, context.cancellationToken));
+
+        return filter(exportClause.elements, element => {
+            return element === originExportSpecifier || findDiagnosticForNode(element, diagnostics)?.code === errorCodes[0];
+        });
+    }
+}
diff --git a/src/services/codefixes/importFixes.ts b/src/services/codefixes/importFixes.ts
index 1581a8b64feb4..e5e141407cb6c 100644
--- a/src/services/codefixes/importFixes.ts
+++ b/src/services/codefixes/importFixes.ts
@@ -30,8 +30,7 @@ namespace ts.codefix {
             const importType: FixUseImportType[] = [];
             // Keys are import clause node IDs.
             const addToExisting = createMap<{ readonly importClause: ImportClause, defaultImport: string | undefined; readonly namedImports: string[] }>();
-            // Keys are module specifiers.
-            const newImports = createMap<Mutable<ImportsCollection>>();
+            const newImports = createNewImportMap();
 
             eachDiagnostic(context, errorCodes, diag => {
                 const info = getFixesInfo(context, diag.code, diag.start);
@@ -63,10 +62,10 @@ namespace ts.codefix {
                         break;
                     }
                     case ImportFixKind.AddNew: {
-                        const { moduleSpecifier, importKind } = fix;
-                        let entry = newImports.get(moduleSpecifier);
+                        const { moduleSpecifier, importKind, typeOnly } = fix;
+                        let entry = newImports.get(moduleSpecifier, typeOnly);
                         if (!entry) {
-                            newImports.set(moduleSpecifier, entry = { defaultImport: undefined, namedImports: [], namespaceLikeImport: undefined });
+                            newImports.set(moduleSpecifier, typeOnly, entry = { defaultImport: undefined, namedImports: [], namespaceLikeImport: undefined });
                         }
                         switch (importKind) {
                             case ImportKind.Default:
@@ -100,13 +99,38 @@ namespace ts.codefix {
                 addToExisting.forEach(({ importClause, defaultImport, namedImports }) => {
                     doAddExistingFix(changes, sourceFile, importClause, defaultImport, namedImports);
                 });
-                newImports.forEach((imports, moduleSpecifier) => {
-                    addNewImports(changes, sourceFile, moduleSpecifier, quotePreference, imports);
+                newImports.forEach((imports, moduleSpecifier, typeOnly) => {
+                    addNewImports(changes, sourceFile, typeOnly, moduleSpecifier, quotePreference, imports);
                 });
             }));
         },
     });
 
+    function createNewImportMap() {
+        // Keys are module specifiers.
+        const newImports = createMap<Mutable<ImportsCollection>>();
+        return {
+            get: (moduleSpecifier: string, typeOnly: boolean) => {
+                return newImports.get(key(moduleSpecifier, typeOnly));
+            },
+            set: (moduleSpecifier: string, typeOnly: boolean, value: ImportsCollection) => {
+                return newImports.set(key(moduleSpecifier, typeOnly), value);
+            },
+            forEach: (action: (value: ImportsCollection, moduleSpecifier: string, typeOnly: boolean) => void) => {
+                newImports.forEach((value, key) => {
+                    const typeOnly = !!+key[0];
+                    const moduleSpecifier = key.slice(1);
+                    action(value, moduleSpecifier, typeOnly);
+                });
+            },
+        };
+
+        function key(moduleSpecifier: string, typeOnly: boolean) {
+            const prefix = typeOnly ? "1" : "0";
+            return prefix + moduleSpecifier;
+        }
+    }
+
     // Sorted with the preferred fix coming first.
     const enum ImportFixKind { UseNamespace, ImportType, AddToExisting, AddNew }
     type ImportFix = FixUseNamespaceImport | FixUseImportType | FixAddToExistingImport | FixAddNewImport;
@@ -129,6 +153,7 @@ namespace ts.codefix {
         readonly kind: ImportFixKind.AddNew;
         readonly moduleSpecifier: string;
         readonly importKind: ImportKind;
+        readonly typeOnly: boolean;
     }
 
     const enum ImportKind {
@@ -151,6 +176,7 @@ namespace ts.codefix {
     interface FixAddToExistingImportInfo {
         readonly declaration: AnyImportSyntax;
         readonly importKind: ImportKind;
+        readonly exportedSymbolIsTypeOnly: boolean;
     }
 
     export function getImportCompletionAction(
@@ -271,7 +297,7 @@ namespace ts.codefix {
         return exportedSymbolIsTypeOnly && isSourceFileJS(sourceFile) ? emptyArray : mapDefined<StringLiteralLike, FixAddToExistingImportInfo>(sourceFile.imports, moduleSpecifier => {
             const i = importFromModuleSpecifier(moduleSpecifier);
             return (i.kind === SyntaxKind.ImportDeclaration || i.kind === SyntaxKind.ImportEqualsDeclaration)
-                && checker.getSymbolAtLocation(moduleSpecifier) === moduleSymbol ? { declaration: i, importKind } : undefined;
+                && checker.getSymbolAtLocation(moduleSpecifier) === moduleSymbol ? { declaration: i, importKind, exportedSymbolIsTypeOnly } : undefined;
         });
     }
 
@@ -291,7 +317,7 @@ namespace ts.codefix {
                     // `position` should only be undefined at a missing jsx namespace, in which case we shouldn't be looking for pure types.
                     exportedSymbolIsTypeOnly && isJs
                         ? { kind: ImportFixKind.ImportType, moduleSpecifier, position: Debug.assertDefined(position, "position should be defined") }
-                        : { kind: ImportFixKind.AddNew, moduleSpecifier, importKind }));
+                        : { kind: ImportFixKind.AddNew, moduleSpecifier, importKind, typeOnly: exportedSymbolIsTypeOnly }));
 
         // Sort by presence in package.json, then shortest paths first
         return sort(choicesForEachExportingModule, (a, b) => {
@@ -320,13 +346,15 @@ namespace ts.codefix {
         return existingDeclaration ? [existingDeclaration] : getNewImportInfos(program, sourceFile, position, exportInfos, host, preferences);
     }
 
-    function newImportInfoFromExistingSpecifier({ declaration, importKind }: FixAddToExistingImportInfo): FixAddNewImport | undefined {
+    function newImportInfoFromExistingSpecifier({ declaration, importKind, exportedSymbolIsTypeOnly }: FixAddToExistingImportInfo): FixAddNewImport | undefined {
         const expression = declaration.kind === SyntaxKind.ImportDeclaration
             ? declaration.moduleSpecifier
             : declaration.moduleReference.kind === SyntaxKind.ExternalModuleReference
                 ? declaration.moduleReference.expression
                 : undefined;
-        return expression && isStringLiteral(expression) ? { kind: ImportFixKind.AddNew, moduleSpecifier: expression.text, importKind } : undefined;
+        return expression && isStringLiteral(expression)
+            ? { kind: ImportFixKind.AddNew, moduleSpecifier: expression.text, importKind, typeOnly: exportedSymbolIsTypeOnly }
+            : undefined;
     }
 
     interface FixesInfo { readonly fixes: readonly ImportFix[]; readonly symbolName: string; }
@@ -532,7 +560,7 @@ namespace ts.codefix {
             }
             case ImportFixKind.AddNew: {
                 const { importKind, moduleSpecifier } = fix;
-                addNewImports(changes, sourceFile, moduleSpecifier, quotePreference, importKind === ImportKind.Default ? { defaultImport: symbolName, namedImports: emptyArray, namespaceLikeImport: undefined }
+                addNewImports(changes, sourceFile, fix.typeOnly, moduleSpecifier, quotePreference, importKind === ImportKind.Default ? { defaultImport: symbolName, namedImports: emptyArray, namespaceLikeImport: undefined }
                     : importKind === ImportKind.Named ? { defaultImport: undefined, namedImports: [symbolName], namespaceLikeImport: undefined }
                     : { defaultImport: undefined, namedImports: emptyArray, namespaceLikeImport: { importKind, name: symbolName } });
                 return [importKind === ImportKind.Default ? Diagnostics.Import_default_0_from_module_1 : Diagnostics.Import_0_from_module_1, symbolName, moduleSpecifier];
@@ -590,13 +618,13 @@ namespace ts.codefix {
             readonly name: string;
         } | undefined;
     }
-    function addNewImports(changes: textChanges.ChangeTracker, sourceFile: SourceFile, moduleSpecifier: string, quotePreference: QuotePreference, { defaultImport, namedImports, namespaceLikeImport }: ImportsCollection): void {
+    function addNewImports(changes: textChanges.ChangeTracker, sourceFile: SourceFile, typeOnly: boolean, moduleSpecifier: string, quotePreference: QuotePreference, { defaultImport, namedImports, namespaceLikeImport }: ImportsCollection): void {
         const quotedModuleSpecifier = makeStringLiteral(moduleSpecifier, quotePreference);
         if (defaultImport !== undefined || namedImports.length) {
             insertImport(changes, sourceFile,
                 makeImport(
                     defaultImport === undefined ? undefined : createIdentifier(defaultImport),
-                    namedImports.map(n => createImportSpecifier(/*propertyName*/ undefined, createIdentifier(n))), moduleSpecifier, quotePreference));
+                    namedImports.map(n => createImportSpecifier(/*propertyName*/ undefined, createIdentifier(n))), moduleSpecifier, quotePreference, typeOnly));
         }
         if (namespaceLikeImport) {
             insertImport(
@@ -604,7 +632,7 @@ namespace ts.codefix {
                 sourceFile,
                 namespaceLikeImport.importKind === ImportKind.Equals ? createImportEqualsDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, createIdentifier(namespaceLikeImport.name), createExternalModuleReference(quotedModuleSpecifier)) :
                 namespaceLikeImport.importKind === ImportKind.ConstEquals ? createConstEqualsRequireDeclaration(namespaceLikeImport.name, quotedModuleSpecifier) :
-                createImportDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, createImportClause(/*name*/ undefined, createNamespaceImport(createIdentifier(namespaceLikeImport.name))), quotedModuleSpecifier));
+                createImportDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, createImportClause(/*name*/ undefined, createNamespaceImport(createIdentifier(namespaceLikeImport.name)), typeOnly), quotedModuleSpecifier));
         }
     }
 
diff --git a/src/services/codefixes/splitTypeOnlyImport.ts b/src/services/codefixes/splitTypeOnlyImport.ts
new file mode 100644
index 0000000000000..e5691a76ab35d
--- /dev/null
+++ b/src/services/codefixes/splitTypeOnlyImport.ts
@@ -0,0 +1,43 @@
+/* @internal */
+namespace ts.codefix {
+    const errorCodes = [Diagnostics.A_type_only_import_can_specify_a_default_import_or_named_bindings_but_not_both.code];
+    const fixId = "splitTypeOnlyImport";
+    registerCodeFix({
+        errorCodes,
+        fixIds: [fixId],
+        getCodeActions: context => {
+            const changes = textChanges.ChangeTracker.with(context, t => {
+                return splitTypeOnlyImport(t, getImportDeclaration(context.sourceFile, context.span), context);
+            });
+            if (changes.length) {
+                return [createCodeFixAction(fixId, changes, Diagnostics.Split_into_two_separate_import_declarations, fixId, Diagnostics.Split_all_invalid_type_only_imports)];
+            }
+        },
+        getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, error) => {
+            splitTypeOnlyImport(changes, getImportDeclaration(context.sourceFile, error), context);
+        }),
+    });
+
+    function getImportDeclaration(sourceFile: SourceFile, span: TextSpan) {
+        return findAncestor(getTokenAtPosition(sourceFile, span.start), isImportDeclaration);
+    }
+
+    function splitTypeOnlyImport(changes: textChanges.ChangeTracker, importDeclaration: ImportDeclaration | undefined, context: CodeFixContextBase) {
+        if (!importDeclaration) {
+            return;
+        }
+        const importClause = Debug.assertDefined(importDeclaration.importClause);
+        changes.replaceNode(context.sourceFile, importDeclaration, updateImportDeclaration(
+            importDeclaration,
+            importDeclaration.decorators,
+            importDeclaration.modifiers,
+            updateImportClause(importClause, importClause.name, /*namedBindings*/ undefined, importClause.isTypeOnly),
+            importDeclaration.moduleSpecifier));
+
+        changes.insertNodeAfter(context.sourceFile, importDeclaration, createImportDeclaration(
+            /*decorators*/ undefined,
+            /*modifiers*/ undefined,
+            updateImportClause(importClause, /*name*/ undefined, importClause.namedBindings, importClause.isTypeOnly),
+            importDeclaration.moduleSpecifier));
+    }
+}
diff --git a/src/services/organizeImports.ts b/src/services/organizeImports.ts
index 232f2c1ba9509..e7731a21f72a1 100644
--- a/src/services/organizeImports.ts
+++ b/src/services/organizeImports.ts
@@ -322,7 +322,8 @@ namespace ts.OrganizeImports {
                         updateNamedExports(exportDecl.exportClause, sortedExportSpecifiers) :
                         updateNamespaceExport(exportDecl.exportClause, exportDecl.exportClause.name)
                 ),
-                exportDecl.moduleSpecifier));
+                exportDecl.moduleSpecifier,
+                exportDecl.isTypeOnly));
 
         return coalescedExports;
 
@@ -362,7 +363,7 @@ namespace ts.OrganizeImports {
             importDeclaration,
             importDeclaration.decorators,
             importDeclaration.modifiers,
-            updateImportClause(importDeclaration.importClause!, name, namedBindings), // TODO: GH#18217
+            updateImportClause(importDeclaration.importClause!, name, namedBindings, importDeclaration.importClause!.isTypeOnly), // TODO: GH#18217
             importDeclaration.moduleSpecifier);
     }
 
diff --git a/src/services/refactors/moveToNewFile.ts b/src/services/refactors/moveToNewFile.ts
index 337afdc4214a6..4a330bcb1afb9 100644
--- a/src/services/refactors/moveToNewFile.ts
+++ b/src/services/refactors/moveToNewFile.ts
@@ -353,7 +353,7 @@ namespace ts.refactor {
                     changes.replaceNode(
                         sourceFile,
                         importDecl.importClause,
-                        updateImportClause(importDecl.importClause, name, /*namedBindings*/ undefined)
+                        updateImportClause(importDecl.importClause, name, /*namedBindings*/ undefined, importDecl.importClause.isTypeOnly)
                     );
                 }
                 else if (namedBindings.kind === SyntaxKind.NamedImports) {
diff --git a/src/services/symbolDisplay.ts b/src/services/symbolDisplay.ts
index faff3620d62c2..d71afe7c39553 100644
--- a/src/services/symbolDisplay.ts
+++ b/src/services/symbolDisplay.ts
@@ -2,6 +2,10 @@
 namespace ts.SymbolDisplay {
     // TODO(drosen): use contextual SemanticMeaning.
     export function getSymbolKind(typeChecker: TypeChecker, symbol: Symbol, location: Node): ScriptElementKind {
+        while (isTypeOnlyAlias(symbol)) {
+            symbol = symbol.immediateTarget;
+        }
+
         const result = getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar(typeChecker, symbol, location);
         if (result !== ScriptElementKind.unknown) {
             return result;
@@ -15,8 +19,6 @@ namespace ts.SymbolDisplay {
         if (flags & SymbolFlags.Enum) return ScriptElementKind.enumElement;
         if (flags & SymbolFlags.TypeAlias) return ScriptElementKind.typeElement;
         if (flags & SymbolFlags.Interface) return ScriptElementKind.interfaceElement;
-        if (flags & SymbolFlags.TypeParameter) return ScriptElementKind.typeParameterElement;
-
         if (flags & SymbolFlags.TypeParameter) return ScriptElementKind.typeParameterElement;
         if (flags & SymbolFlags.EnumMember) return ScriptElementKind.enumMemberElement;
         if (flags & SymbolFlags.Alias) return ScriptElementKind.alias;
@@ -124,6 +126,10 @@ namespace ts.SymbolDisplay {
     export function getSymbolDisplayPartsDocumentationAndSymbolKind(typeChecker: TypeChecker, symbol: Symbol, sourceFile: SourceFile, enclosingDeclaration: Node | undefined,
         location: Node, semanticMeaning = getMeaningFromLocation(location), alias?: Symbol): SymbolDisplayPartsDocumentationAndSymbolKind {
 
+        while (isTypeOnlyAlias(symbol)) {
+            symbol = symbol.immediateTarget;
+        }
+
         const displayParts: SymbolDisplayPart[] = [];
         let documentation: SymbolDisplayPart[] | undefined;
         let tags: JSDocTagInfo[] | undefined;
diff --git a/src/services/tsconfig.json b/src/services/tsconfig.json
index 674b0076848d4..c1b95bf8fca81 100644
--- a/src/services/tsconfig.json
+++ b/src/services/tsconfig.json
@@ -58,6 +58,7 @@
         "codefixes/convertToAsyncFunction.ts",
         "codefixes/convertToEs6Module.ts",
         "codefixes/correctQualifiedNameToIndexedAccessType.ts",
+        "codefixes/convertToTypeOnlyExport.ts",
         "codefixes/fixClassIncorrectlyImplementsInterface.ts",
         "codefixes/importFixes.ts",
         "codefixes/fixSpelling.ts",
@@ -86,6 +87,7 @@
         "codefixes/fixAddModuleReferTypeMissingTypeof.ts",
         "codefixes/convertToMappedObjectType.ts",
         "codefixes/removeUnnecessaryAwait.ts",
+        "codefixes/splitTypeOnlyImport.ts",
         "codefixes/convertConstToLet.ts",
         "refactors/convertExport.ts",
         "refactors/convertImport.ts",
diff --git a/src/services/utilities.ts b/src/services/utilities.ts
index 39ce286486b7a..10a14b9ee8ceb 100644
--- a/src/services/utilities.ts
+++ b/src/services/utilities.ts
@@ -1357,12 +1357,12 @@ namespace ts {
         return defaultImport || namedImports && namedImports.length ? makeImport(defaultImport, namedImports, moduleSpecifier, quotePreference) : undefined;
     }
 
-    export function makeImport(defaultImport: Identifier | undefined, namedImports: readonly ImportSpecifier[] | undefined, moduleSpecifier: string | Expression, quotePreference: QuotePreference): ImportDeclaration {
+    export function makeImport(defaultImport: Identifier | undefined, namedImports: readonly ImportSpecifier[] | undefined, moduleSpecifier: string | Expression, quotePreference: QuotePreference, isTypeOnly?: boolean): ImportDeclaration {
         return createImportDeclaration(
             /*decorators*/ undefined,
             /*modifiers*/ undefined,
             defaultImport || namedImports
-                ? createImportClause(defaultImport, namedImports && namedImports.length ? createNamedImports(namedImports) : undefined)
+                ? createImportClause(defaultImport, namedImports && namedImports.length ? createNamedImports(namedImports) : undefined, isTypeOnly)
                 : undefined,
             typeof moduleSpecifier === "string" ? makeStringLiteral(moduleSpecifier, quotePreference) : moduleSpecifier);
     }
@@ -2326,7 +2326,45 @@ namespace ts {
     export function isInsideNodeModules(fileOrDirectory: string): boolean {
         return contains(getPathComponents(fileOrDirectory), "node_modules");
     }
-    // #endregion
+
+    export function isDiagnosticWithLocation(diagnostic: Diagnostic): diagnostic is DiagnosticWithLocation {
+        return diagnostic.file !== undefined && diagnostic.start !== undefined && diagnostic.length !== undefined;
+    }
+
+    export function findDiagnosticForNode(node: Node, sortedFileDiagnostics: readonly Diagnostic[]): DiagnosticWithLocation | undefined {
+        const span: Partial<TextSpan> = createTextSpanFromNode(node);
+        const index = binarySearchKey(sortedFileDiagnostics, span, identity, compareTextSpans);
+        if (index >= 0) {
+            const diagnostic = sortedFileDiagnostics[index];
+            Debug.assertEqual(diagnostic.file, node.getSourceFile(), "Diagnostics proided to 'findDiagnosticForNode' must be from a single SourceFile");
+            return cast(diagnostic, isDiagnosticWithLocation);
+        }
+    }
+
+    export function getDiagnosticsWithinSpan(span: TextSpan, sortedFileDiagnostics: readonly Diagnostic[]): readonly DiagnosticWithLocation[] {
+        let index = binarySearchKey(sortedFileDiagnostics, span.start, diag => diag.start, compareValues);
+        if (index < 0) {
+            index = ~index;
+        }
+        while (sortedFileDiagnostics[index - 1]?.start === span.start) {
+            index--;
+        }
+
+        const result: DiagnosticWithLocation[] = [];
+        const end = textSpanEnd(span);
+        while (true) {
+            const diagnostic = tryCast(sortedFileDiagnostics[index], isDiagnosticWithLocation);
+            if (!diagnostic || diagnostic.start > end) {
+                break;
+            }
+            if (textSpanContainsTextSpan(span, diagnostic)) {
+                result.push(diagnostic);
+            }
+            index++;
+        }
+
+        return result;
+    }
 
     /* @internal */
     export function getRefactorContextSpan({ startPosition, endPosition }: RefactorContext): TextSpan {
@@ -2351,4 +2389,6 @@ namespace ts {
     export function firstOrOnly<T>(valueOrArray: T | readonly T[]): T {
         return isArray(valueOrArray) ? first(valueOrArray) : valueOrArray;
     }
+
+    // #endregion
 }
diff --git a/src/testRunner/unittests/transform.ts b/src/testRunner/unittests/transform.ts
index fd5b54d3565f5..b244b942a503c 100644
--- a/src/testRunner/unittests/transform.ts
+++ b/src/testRunner/unittests/transform.ts
@@ -231,7 +231,7 @@ namespace ts {
                             const exports = [{ name: "x" }];
                             const exportSpecifiers = exports.map(e => createExportSpecifier(e.name, e.name));
                             const exportClause = createNamedExports(exportSpecifiers);
-                            const newEd = updateExportDeclaration(ed, ed.decorators, ed.modifiers, exportClause, ed.moduleSpecifier);
+                            const newEd = updateExportDeclaration(ed, ed.decorators, ed.modifiers, exportClause, ed.moduleSpecifier, ed.isTypeOnly);
 
                             return newEd as Node as T;
                         }
diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts
index 0ac0f4c227ee4..5b8624ae0310d 100644
--- a/tests/baselines/reference/api/tsserverlibrary.d.ts
+++ b/tests/baselines/reference/api/tsserverlibrary.d.ts
@@ -1496,6 +1496,7 @@ declare namespace ts {
     export interface ImportClause extends NamedDeclaration {
         kind: SyntaxKind.ImportClause;
         parent: ImportDeclaration;
+        isTypeOnly: boolean;
         name?: Identifier;
         namedBindings?: NamedImportBindings;
     }
@@ -1516,6 +1517,7 @@ declare namespace ts {
     export interface ExportDeclaration extends DeclarationStatement, JSDocContainer {
         kind: SyntaxKind.ExportDeclaration;
         parent: SourceFile | ModuleBlock;
+        isTypeOnly: boolean;
         /** Will not be assigned in the case of `export * from "foo";` */
         exportClause?: NamedExportBindings;
         /** If this is not a StringLiteral it will be a grammar error. */
@@ -2649,6 +2651,7 @@ declare namespace ts {
         experimentalDecorators?: boolean;
         forceConsistentCasingInFileNames?: boolean;
         importHelpers?: boolean;
+        importsNotUsedAsValue?: ImportsNotUsedAsValue;
         inlineSourceMap?: boolean;
         inlineSources?: boolean;
         isolatedModules?: boolean;
@@ -2746,6 +2749,11 @@ declare namespace ts {
         React = 2,
         ReactNative = 3
     }
+    export enum ImportsNotUsedAsValue {
+        Remove = 0,
+        Preserve = 1,
+        Error = 2
+    }
     export enum NewLineKind {
         CarriageReturnLineFeed = 0,
         LineFeed = 1
@@ -3730,6 +3738,7 @@ declare namespace ts {
     function isTemplateLiteralToken(node: Node): node is TemplateLiteralToken;
     function isTemplateMiddleOrTemplateTail(node: Node): node is TemplateMiddle | TemplateTail;
     function isImportOrExportSpecifier(node: Node): node is ImportSpecifier | ExportSpecifier;
+    function isTypeOnlyImportOrExportName(node: Node): boolean;
     function isStringTextContainingNode(node: Node): node is StringLiteral | TemplateLiteralToken;
     function isModifier(node: Node): node is Modifier;
     function isEntityName(node: Node): node is EntityName;
@@ -4176,8 +4185,8 @@ declare namespace ts {
     function updateImportEqualsDeclaration(node: ImportEqualsDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: Identifier, moduleReference: ModuleReference): ImportEqualsDeclaration;
     function createImportDeclaration(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression): ImportDeclaration;
     function updateImportDeclaration(node: ImportDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression): ImportDeclaration;
-    function createImportClause(name: Identifier | undefined, namedBindings: NamedImportBindings | undefined): ImportClause;
-    function updateImportClause(node: ImportClause, name: Identifier | undefined, namedBindings: NamedImportBindings | undefined): ImportClause;
+    function createImportClause(name: Identifier | undefined, namedBindings: NamedImportBindings | undefined, isTypeOnly?: boolean): ImportClause;
+    function updateImportClause(node: ImportClause, name: Identifier | undefined, namedBindings: NamedImportBindings | undefined, isTypeOnly: boolean): ImportClause;
     function createNamespaceImport(name: Identifier): NamespaceImport;
     function createNamespaceExport(name: Identifier): NamespaceExport;
     function updateNamespaceImport(node: NamespaceImport, name: Identifier): NamespaceImport;
@@ -4188,8 +4197,8 @@ declare namespace ts {
     function updateImportSpecifier(node: ImportSpecifier, propertyName: Identifier | undefined, name: Identifier): ImportSpecifier;
     function createExportAssignment(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, isExportEquals: boolean | undefined, expression: Expression): ExportAssignment;
     function updateExportAssignment(node: ExportAssignment, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, expression: Expression): ExportAssignment;
-    function createExportDeclaration(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, exportClause: NamedExportBindings | undefined, moduleSpecifier?: Expression): ExportDeclaration;
-    function updateExportDeclaration(node: ExportDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, exportClause: NamedExportBindings | undefined, moduleSpecifier: Expression | undefined): ExportDeclaration;
+    function createExportDeclaration(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, exportClause: NamedExportBindings | undefined, moduleSpecifier?: Expression, isTypeOnly?: boolean): ExportDeclaration;
+    function updateExportDeclaration(node: ExportDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, exportClause: NamedExportBindings | undefined, moduleSpecifier: Expression | undefined, isTypeOnly: boolean): ExportDeclaration;
     function createNamedExports(elements: readonly ExportSpecifier[]): NamedExports;
     function updateNamedExports(node: NamedExports, elements: readonly ExportSpecifier[]): NamedExports;
     function createExportSpecifier(propertyName: string | Identifier | undefined, name: string | Identifier): ExportSpecifier;
diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts
index 42432eac6e783..65e91049d3319 100644
--- a/tests/baselines/reference/api/typescript.d.ts
+++ b/tests/baselines/reference/api/typescript.d.ts
@@ -1496,6 +1496,7 @@ declare namespace ts {
     export interface ImportClause extends NamedDeclaration {
         kind: SyntaxKind.ImportClause;
         parent: ImportDeclaration;
+        isTypeOnly: boolean;
         name?: Identifier;
         namedBindings?: NamedImportBindings;
     }
@@ -1516,6 +1517,7 @@ declare namespace ts {
     export interface ExportDeclaration extends DeclarationStatement, JSDocContainer {
         kind: SyntaxKind.ExportDeclaration;
         parent: SourceFile | ModuleBlock;
+        isTypeOnly: boolean;
         /** Will not be assigned in the case of `export * from "foo";` */
         exportClause?: NamedExportBindings;
         /** If this is not a StringLiteral it will be a grammar error. */
@@ -2649,6 +2651,7 @@ declare namespace ts {
         experimentalDecorators?: boolean;
         forceConsistentCasingInFileNames?: boolean;
         importHelpers?: boolean;
+        importsNotUsedAsValue?: ImportsNotUsedAsValue;
         inlineSourceMap?: boolean;
         inlineSources?: boolean;
         isolatedModules?: boolean;
@@ -2746,6 +2749,11 @@ declare namespace ts {
         React = 2,
         ReactNative = 3
     }
+    export enum ImportsNotUsedAsValue {
+        Remove = 0,
+        Preserve = 1,
+        Error = 2
+    }
     export enum NewLineKind {
         CarriageReturnLineFeed = 0,
         LineFeed = 1
@@ -3730,6 +3738,7 @@ declare namespace ts {
     function isTemplateLiteralToken(node: Node): node is TemplateLiteralToken;
     function isTemplateMiddleOrTemplateTail(node: Node): node is TemplateMiddle | TemplateTail;
     function isImportOrExportSpecifier(node: Node): node is ImportSpecifier | ExportSpecifier;
+    function isTypeOnlyImportOrExportName(node: Node): boolean;
     function isStringTextContainingNode(node: Node): node is StringLiteral | TemplateLiteralToken;
     function isModifier(node: Node): node is Modifier;
     function isEntityName(node: Node): node is EntityName;
@@ -4176,8 +4185,8 @@ declare namespace ts {
     function updateImportEqualsDeclaration(node: ImportEqualsDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: Identifier, moduleReference: ModuleReference): ImportEqualsDeclaration;
     function createImportDeclaration(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression): ImportDeclaration;
     function updateImportDeclaration(node: ImportDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression): ImportDeclaration;
-    function createImportClause(name: Identifier | undefined, namedBindings: NamedImportBindings | undefined): ImportClause;
-    function updateImportClause(node: ImportClause, name: Identifier | undefined, namedBindings: NamedImportBindings | undefined): ImportClause;
+    function createImportClause(name: Identifier | undefined, namedBindings: NamedImportBindings | undefined, isTypeOnly?: boolean): ImportClause;
+    function updateImportClause(node: ImportClause, name: Identifier | undefined, namedBindings: NamedImportBindings | undefined, isTypeOnly: boolean): ImportClause;
     function createNamespaceImport(name: Identifier): NamespaceImport;
     function createNamespaceExport(name: Identifier): NamespaceExport;
     function updateNamespaceImport(node: NamespaceImport, name: Identifier): NamespaceImport;
@@ -4188,8 +4197,8 @@ declare namespace ts {
     function updateImportSpecifier(node: ImportSpecifier, propertyName: Identifier | undefined, name: Identifier): ImportSpecifier;
     function createExportAssignment(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, isExportEquals: boolean | undefined, expression: Expression): ExportAssignment;
     function updateExportAssignment(node: ExportAssignment, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, expression: Expression): ExportAssignment;
-    function createExportDeclaration(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, exportClause: NamedExportBindings | undefined, moduleSpecifier?: Expression): ExportDeclaration;
-    function updateExportDeclaration(node: ExportDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, exportClause: NamedExportBindings | undefined, moduleSpecifier: Expression | undefined): ExportDeclaration;
+    function createExportDeclaration(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, exportClause: NamedExportBindings | undefined, moduleSpecifier?: Expression, isTypeOnly?: boolean): ExportDeclaration;
+    function updateExportDeclaration(node: ExportDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, exportClause: NamedExportBindings | undefined, moduleSpecifier: Expression | undefined, isTypeOnly: boolean): ExportDeclaration;
     function createNamedExports(elements: readonly ExportSpecifier[]): NamedExports;
     function updateNamedExports(node: NamedExports, elements: readonly ExportSpecifier[]): NamedExports;
     function createExportSpecifier(propertyName: string | Identifier | undefined, name: string | Identifier): ExportSpecifier;
diff --git a/tests/baselines/reference/awaitInNonAsyncFunction.errors.txt b/tests/baselines/reference/awaitInNonAsyncFunction.errors.txt
index d7706ed107422..aa07a57b57ce2 100644
--- a/tests/baselines/reference/awaitInNonAsyncFunction.errors.txt
+++ b/tests/baselines/reference/awaitInNonAsyncFunction.errors.txt
@@ -13,7 +13,7 @@ tests/cases/compiler/awaitInNonAsyncFunction.ts(31,5): error TS1308: 'await' exp
 tests/cases/compiler/awaitInNonAsyncFunction.ts(34,7): error TS1103: A 'for-await-of' statement is only allowed within an async function or async generator.
 tests/cases/compiler/awaitInNonAsyncFunction.ts(35,5): error TS1308: 'await' expression is only allowed within an async function.
 tests/cases/compiler/awaitInNonAsyncFunction.ts(39,5): error TS1103: A 'for-await-of' statement is only allowed within an async function or async generator.
-tests/cases/compiler/awaitInNonAsyncFunction.ts(40,1): error TS1361: 'await' outside of an async function is only allowed at the top level of a module when '--module' is 'esnext' or 'system' and '--target' is 'es2017' or higher.
+tests/cases/compiler/awaitInNonAsyncFunction.ts(40,1): error TS1375: 'await' outside of an async function is only allowed at the top level of a module when '--module' is 'esnext' or 'system' and '--target' is 'es2017' or higher.
 
 
 ==== tests/cases/compiler/awaitInNonAsyncFunction.ts (16 errors) ====
@@ -100,4 +100,4 @@ tests/cases/compiler/awaitInNonAsyncFunction.ts(40,1): error TS1361: 'await' out
 !!! error TS1103: A 'for-await-of' statement is only allowed within an async function or async generator.
     await null;
     ~~~~~
-!!! error TS1361: 'await' outside of an async function is only allowed at the top level of a module when '--module' is 'esnext' or 'system' and '--target' is 'es2017' or higher.
\ No newline at end of file
+!!! error TS1375: 'await' outside of an async function is only allowed at the top level of a module when '--module' is 'esnext' or 'system' and '--target' is 'es2017' or higher.
\ No newline at end of file
diff --git a/tests/baselines/reference/chained.errors.txt b/tests/baselines/reference/chained.errors.txt
new file mode 100644
index 0000000000000..8d684afbb9475
--- /dev/null
+++ b/tests/baselines/reference/chained.errors.txt
@@ -0,0 +1,27 @@
+/d.ts(2,5): error TS2693: 'D' only refers to a type, but is being used as a value here.
+/d.ts(3,7): error TS2741: Property 'a' is missing in type '{}' but required in type 'A'.
+
+
+==== /a.ts (0 errors) ====
+    class A { a!: string }
+    export type { A as B };
+    export type Z = A;
+    
+==== /b.ts (0 errors) ====
+    import { Z as Y } from './a';
+    export { B as C } from './a';
+    
+==== /c.ts (0 errors) ====
+    import type { C } from './b';
+    export { C as D };
+    
+==== /d.ts (2 errors) ====
+    import { D } from './c';
+    new D();
+        ~
+!!! error TS2693: 'D' only refers to a type, but is being used as a value here.
+    const d: D = {};
+          ~
+!!! error TS2741: Property 'a' is missing in type '{}' but required in type 'A'.
+!!! related TS2728 /a.ts:1:11: 'a' is declared here.
+    
\ No newline at end of file
diff --git a/tests/baselines/reference/chained.js b/tests/baselines/reference/chained.js
new file mode 100644
index 0000000000000..e37d6361b2441
--- /dev/null
+++ b/tests/baselines/reference/chained.js
@@ -0,0 +1,40 @@
+//// [tests/cases/conformance/externalModules/typeOnly/chained.ts] ////
+
+//// [a.ts]
+class A { a!: string }
+export type { A as B };
+export type Z = A;
+
+//// [b.ts]
+import { Z as Y } from './a';
+export { B as C } from './a';
+
+//// [c.ts]
+import type { C } from './b';
+export { C as D };
+
+//// [d.ts]
+import { D } from './c';
+new D();
+const d: D = {};
+
+
+//// [a.js]
+"use strict";
+exports.__esModule = true;
+var A = /** @class */ (function () {
+    function A() {
+    }
+    return A;
+}());
+//// [b.js]
+"use strict";
+exports.__esModule = true;
+//// [c.js]
+"use strict";
+exports.__esModule = true;
+//// [d.js]
+"use strict";
+exports.__esModule = true;
+new D();
+var d = {};
diff --git a/tests/baselines/reference/chained.symbols b/tests/baselines/reference/chained.symbols
new file mode 100644
index 0000000000000..9ba6d5bed2142
--- /dev/null
+++ b/tests/baselines/reference/chained.symbols
@@ -0,0 +1,39 @@
+=== /a.ts ===
+class A { a!: string }
+>A : Symbol(A, Decl(a.ts, 0, 0))
+>a : Symbol(A.a, Decl(a.ts, 0, 9))
+
+export type { A as B };
+>A : Symbol(A)
+>B : Symbol(B, Decl(a.ts, 1, 13))
+
+export type Z = A;
+>Z : Symbol(Z, Decl(a.ts, 1, 23))
+>A : Symbol(A, Decl(a.ts, 0, 0))
+
+=== /b.ts ===
+import { Z as Y } from './a';
+>Z : Symbol(Y, Decl(a.ts, 1, 23))
+>Y : Symbol(Y, Decl(b.ts, 0, 8))
+
+export { B as C } from './a';
+>B : Symbol(B, Decl(a.ts, 1, 13))
+>C : Symbol(C, Decl(b.ts, 1, 8))
+
+=== /c.ts ===
+import type { C } from './b';
+>C : Symbol(C, Decl(c.ts, 0, 13))
+
+export { C as D };
+>C : Symbol(C, Decl(c.ts, 0, 13))
+>D : Symbol(D, Decl(c.ts, 1, 8))
+
+=== /d.ts ===
+import { D } from './c';
+>D : Symbol(D, Decl(d.ts, 0, 8))
+
+new D();
+const d: D = {};
+>d : Symbol(d, Decl(d.ts, 2, 5))
+>D : Symbol(D, Decl(d.ts, 0, 8))
+
diff --git a/tests/baselines/reference/chained.types b/tests/baselines/reference/chained.types
new file mode 100644
index 0000000000000..5e52f608b821b
--- /dev/null
+++ b/tests/baselines/reference/chained.types
@@ -0,0 +1,41 @@
+=== /a.ts ===
+class A { a!: string }
+>A : A
+>a : string
+
+export type { A as B };
+>A : A
+>B : A
+
+export type Z = A;
+>Z : A
+
+=== /b.ts ===
+import { Z as Y } from './a';
+>Z : any
+>Y : any
+
+export { B as C } from './a';
+>B : any
+>C : any
+
+=== /c.ts ===
+import type { C } from './b';
+>C : A
+
+export { C as D };
+>C : any
+>D : any
+
+=== /d.ts ===
+import { D } from './c';
+>D : any
+
+new D();
+>new D() : any
+>D : any
+
+const d: D = {};
+>d : A
+>{} : {}
+
diff --git a/tests/baselines/reference/circular1.errors.txt b/tests/baselines/reference/circular1.errors.txt
new file mode 100644
index 0000000000000..eb583371b3d72
--- /dev/null
+++ b/tests/baselines/reference/circular1.errors.txt
@@ -0,0 +1,11 @@
+/b.ts(1,15): error TS2303: Circular definition of import alias 'A'.
+
+
+==== /a.ts (0 errors) ====
+    export type { A } from './b';
+    
+==== /b.ts (1 errors) ====
+    export type { A } from './a';
+                  ~
+!!! error TS2303: Circular definition of import alias 'A'.
+    
\ No newline at end of file
diff --git a/tests/baselines/reference/circular1.symbols b/tests/baselines/reference/circular1.symbols
new file mode 100644
index 0000000000000..be98e672c1bcc
--- /dev/null
+++ b/tests/baselines/reference/circular1.symbols
@@ -0,0 +1,8 @@
+=== /a.ts ===
+export type { A } from './b';
+>A : Symbol(A, Decl(a.ts, 0, 13))
+
+=== /b.ts ===
+export type { A } from './a';
+>A : Symbol(A, Decl(b.ts, 0, 13))
+
diff --git a/tests/baselines/reference/circular1.types b/tests/baselines/reference/circular1.types
new file mode 100644
index 0000000000000..32a8ee27d8ce0
--- /dev/null
+++ b/tests/baselines/reference/circular1.types
@@ -0,0 +1,8 @@
+=== /a.ts ===
+export type { A } from './b';
+>A : any
+
+=== /b.ts ===
+export type { A } from './a';
+>A : any
+
diff --git a/tests/baselines/reference/circular2.errors.txt b/tests/baselines/reference/circular2.errors.txt
new file mode 100644
index 0000000000000..9906fc8fa88e0
--- /dev/null
+++ b/tests/baselines/reference/circular2.errors.txt
@@ -0,0 +1,16 @@
+/a.ts(2,13): error TS2456: Type alias 'A' circularly references itself.
+/b.ts(2,13): error TS2456: Type alias 'B' circularly references itself.
+
+
+==== /a.ts (1 errors) ====
+    import type { B } from './b';
+    export type A = B;
+                ~
+!!! error TS2456: Type alias 'A' circularly references itself.
+    
+==== /b.ts (1 errors) ====
+    import type { A } from './a';
+    export type B = A;
+                ~
+!!! error TS2456: Type alias 'B' circularly references itself.
+    
\ No newline at end of file
diff --git a/tests/baselines/reference/circular2.symbols b/tests/baselines/reference/circular2.symbols
new file mode 100644
index 0000000000000..1303d78e0a6a6
--- /dev/null
+++ b/tests/baselines/reference/circular2.symbols
@@ -0,0 +1,16 @@
+=== /a.ts ===
+import type { B } from './b';
+>B : Symbol(B, Decl(a.ts, 0, 13))
+
+export type A = B;
+>A : Symbol(A, Decl(a.ts, 0, 29))
+>B : Symbol(B, Decl(a.ts, 0, 13))
+
+=== /b.ts ===
+import type { A } from './a';
+>A : Symbol(A, Decl(b.ts, 0, 13))
+
+export type B = A;
+>B : Symbol(B, Decl(b.ts, 0, 29))
+>A : Symbol(A, Decl(b.ts, 0, 13))
+
diff --git a/tests/baselines/reference/circular2.types b/tests/baselines/reference/circular2.types
new file mode 100644
index 0000000000000..cea0b396bd042
--- /dev/null
+++ b/tests/baselines/reference/circular2.types
@@ -0,0 +1,14 @@
+=== /a.ts ===
+import type { B } from './b';
+>B : any
+
+export type A = B;
+>A : any
+
+=== /b.ts ===
+import type { A } from './a';
+>A : any
+
+export type B = A;
+>B : any
+
diff --git a/tests/baselines/reference/circular3.errors.txt b/tests/baselines/reference/circular3.errors.txt
new file mode 100644
index 0000000000000..5da3e364065b2
--- /dev/null
+++ b/tests/baselines/reference/circular3.errors.txt
@@ -0,0 +1,13 @@
+/b.ts(1,15): error TS2303: Circular definition of import alias 'B'.
+
+
+==== /a.ts (0 errors) ====
+    import type { A } from './b';
+    export type { A as B };
+    
+==== /b.ts (1 errors) ====
+    import type { B } from './a';
+                  ~
+!!! error TS2303: Circular definition of import alias 'B'.
+    export type { B as A };
+    
\ No newline at end of file
diff --git a/tests/baselines/reference/circular3.symbols b/tests/baselines/reference/circular3.symbols
new file mode 100644
index 0000000000000..6cdec14d30cbd
--- /dev/null
+++ b/tests/baselines/reference/circular3.symbols
@@ -0,0 +1,16 @@
+=== /a.ts ===
+import type { A } from './b';
+>A : Symbol(A, Decl(a.ts, 0, 13))
+
+export type { A as B };
+>A : Symbol(A, Decl(a.ts, 0, 13))
+>B : Symbol(B, Decl(a.ts, 1, 13))
+
+=== /b.ts ===
+import type { B } from './a';
+>B : Symbol(B, Decl(b.ts, 0, 13))
+
+export type { B as A };
+>B : Symbol(B, Decl(b.ts, 0, 13))
+>A : Symbol(A, Decl(b.ts, 1, 13))
+
diff --git a/tests/baselines/reference/circular3.types b/tests/baselines/reference/circular3.types
new file mode 100644
index 0000000000000..1c63897fba59d
--- /dev/null
+++ b/tests/baselines/reference/circular3.types
@@ -0,0 +1,16 @@
+=== /a.ts ===
+import type { A } from './b';
+>A : any
+
+export type { A as B };
+>A : any
+>B : any
+
+=== /b.ts ===
+import type { B } from './a';
+>B : any
+
+export type { B as A };
+>B : any
+>A : any
+
diff --git a/tests/baselines/reference/circular4.errors.txt b/tests/baselines/reference/circular4.errors.txt
new file mode 100644
index 0000000000000..b55cab7bf7c56
--- /dev/null
+++ b/tests/baselines/reference/circular4.errors.txt
@@ -0,0 +1,24 @@
+/a.ts(4,17): error TS2456: Type alias 'T' circularly references itself.
+/b.ts(4,17): error TS2456: Type alias 'T' circularly references itself.
+
+
+==== /a.ts (1 errors) ====
+    import type { ns2 } from './b';
+    export namespace ns1 {
+      export namespace nested {
+        export type T = ns2.nested.T;
+                    ~
+!!! error TS2456: Type alias 'T' circularly references itself.
+      }
+    }
+    
+==== /b.ts (1 errors) ====
+    import type { ns1 } from './a';
+    export namespace ns2 {
+      export namespace nested {
+        export type T = ns1.nested.T;
+                    ~
+!!! error TS2456: Type alias 'T' circularly references itself.
+      }
+    }
+    
\ No newline at end of file
diff --git a/tests/baselines/reference/circular4.symbols b/tests/baselines/reference/circular4.symbols
new file mode 100644
index 0000000000000..980ac1720f256
--- /dev/null
+++ b/tests/baselines/reference/circular4.symbols
@@ -0,0 +1,36 @@
+=== /a.ts ===
+import type { ns2 } from './b';
+>ns2 : Symbol(ns2, Decl(a.ts, 0, 13))
+
+export namespace ns1 {
+>ns1 : Symbol(ns1, Decl(a.ts, 0, 31))
+
+  export namespace nested {
+>nested : Symbol(nested, Decl(a.ts, 1, 22))
+
+    export type T = ns2.nested.T;
+>T : Symbol(T, Decl(a.ts, 2, 27))
+>ns2 : Symbol(ns2, Decl(a.ts, 0, 13))
+>nested : Symbol(ns2.nested, Decl(b.ts, 1, 22))
+>T : Symbol(ns2.nested.T, Decl(b.ts, 2, 27))
+  }
+}
+
+=== /b.ts ===
+import type { ns1 } from './a';
+>ns1 : Symbol(ns1, Decl(b.ts, 0, 13))
+
+export namespace ns2 {
+>ns2 : Symbol(ns2, Decl(b.ts, 0, 31))
+
+  export namespace nested {
+>nested : Symbol(nested, Decl(b.ts, 1, 22))
+
+    export type T = ns1.nested.T;
+>T : Symbol(T, Decl(b.ts, 2, 27))
+>ns1 : Symbol(ns1, Decl(b.ts, 0, 13))
+>nested : Symbol(ns1.nested, Decl(a.ts, 1, 22))
+>T : Symbol(ns1.nested.T, Decl(a.ts, 2, 27))
+  }
+}
+
diff --git a/tests/baselines/reference/circular4.types b/tests/baselines/reference/circular4.types
new file mode 100644
index 0000000000000..491c36e6c16b1
--- /dev/null
+++ b/tests/baselines/reference/circular4.types
@@ -0,0 +1,26 @@
+=== /a.ts ===
+import type { ns2 } from './b';
+>ns2 : any
+
+export namespace ns1 {
+  export namespace nested {
+    export type T = ns2.nested.T;
+>T : any
+>ns2 : any
+>nested : any
+  }
+}
+
+=== /b.ts ===
+import type { ns1 } from './a';
+>ns1 : any
+
+export namespace ns2 {
+  export namespace nested {
+    export type T = ns1.nested.T;
+>T : any
+>ns1 : any
+>nested : any
+  }
+}
+
diff --git a/tests/baselines/reference/enums.errors.txt b/tests/baselines/reference/enums.errors.txt
new file mode 100644
index 0000000000000..4e874cbee48dc
--- /dev/null
+++ b/tests/baselines/reference/enums.errors.txt
@@ -0,0 +1,38 @@
+/b.ts(3,1): error TS1362: Enum 'SyntaxKind' cannot be used as a value because only its type has been imported.
+/b.ts(4,1): error TS1362: Enum 'SymbolFlags' cannot be used as a value because only its type has been imported.
+
+
+==== /a.ts (0 errors) ====
+    enum SyntaxKind {
+      ImportClause,
+      ExportDeclaration
+    }
+    
+    const enum SymbolFlags {
+      Type = "Type",
+      Value = "Value"
+    }
+    
+    export type { SyntaxKind };
+    export { SymbolFlags };
+    
+==== /b.ts (2 errors) ====
+    import type { SyntaxKind, SymbolFlags } from './a';
+    
+    SyntaxKind.ImportClause;
+    ~~~~~~~~~~
+!!! error TS1362: Enum 'SyntaxKind' cannot be used as a value because only its type has been imported.
+    SymbolFlags.Type;
+    ~~~~~~~~~~~
+!!! error TS1362: Enum 'SymbolFlags' cannot be used as a value because only its type has been imported.
+    let kind: SyntaxKind.ImportClause;
+    let flags: SymbolFlags;
+    
+    type TypeFlag = SymbolFlags.Type;
+    export type { TypeFlag };
+    
+==== /c.ts (0 errors) ====
+    import { SymbolFlags } from './a';
+    import type { TypeFlag } from './b';
+    const flags: TypeFlag = SymbolFlags.Type;
+    
\ No newline at end of file
diff --git a/tests/baselines/reference/enums.js b/tests/baselines/reference/enums.js
new file mode 100644
index 0000000000000..09243e4a7f134
--- /dev/null
+++ b/tests/baselines/reference/enums.js
@@ -0,0 +1,52 @@
+//// [tests/cases/conformance/externalModules/typeOnly/enums.ts] ////
+
+//// [a.ts]
+enum SyntaxKind {
+  ImportClause,
+  ExportDeclaration
+}
+
+const enum SymbolFlags {
+  Type = "Type",
+  Value = "Value"
+}
+
+export type { SyntaxKind };
+export { SymbolFlags };
+
+//// [b.ts]
+import type { SyntaxKind, SymbolFlags } from './a';
+
+SyntaxKind.ImportClause;
+SymbolFlags.Type;
+let kind: SyntaxKind.ImportClause;
+let flags: SymbolFlags;
+
+type TypeFlag = SymbolFlags.Type;
+export type { TypeFlag };
+
+//// [c.ts]
+import { SymbolFlags } from './a';
+import type { TypeFlag } from './b';
+const flags: TypeFlag = SymbolFlags.Type;
+
+
+//// [a.js]
+"use strict";
+exports.__esModule = true;
+var SyntaxKind;
+(function (SyntaxKind) {
+    SyntaxKind[SyntaxKind["ImportClause"] = 0] = "ImportClause";
+    SyntaxKind[SyntaxKind["ExportDeclaration"] = 1] = "ExportDeclaration";
+})(SyntaxKind || (SyntaxKind = {}));
+//// [b.js]
+"use strict";
+exports.__esModule = true;
+SyntaxKind.ImportClause;
+SymbolFlags.Type;
+var kind;
+var flags;
+//// [c.js]
+"use strict";
+exports.__esModule = true;
+var flags = "Type" /* Type */;
diff --git a/tests/baselines/reference/enums.symbols b/tests/baselines/reference/enums.symbols
new file mode 100644
index 0000000000000..edac3617acbee
--- /dev/null
+++ b/tests/baselines/reference/enums.symbols
@@ -0,0 +1,65 @@
+=== /a.ts ===
+enum SyntaxKind {
+>SyntaxKind : Symbol(SyntaxKind, Decl(a.ts, 0, 0))
+
+  ImportClause,
+>ImportClause : Symbol(SyntaxKind.ImportClause, Decl(a.ts, 0, 17))
+
+  ExportDeclaration
+>ExportDeclaration : Symbol(SyntaxKind.ExportDeclaration, Decl(a.ts, 1, 15))
+}
+
+const enum SymbolFlags {
+>SymbolFlags : Symbol(SymbolFlags, Decl(a.ts, 3, 1))
+
+  Type = "Type",
+>Type : Symbol(SymbolFlags.Type, Decl(a.ts, 5, 24))
+
+  Value = "Value"
+>Value : Symbol(SymbolFlags.Value, Decl(a.ts, 6, 16))
+}
+
+export type { SyntaxKind };
+>SyntaxKind : Symbol(SyntaxKind, Decl(a.ts, 10, 13))
+
+export { SymbolFlags };
+>SymbolFlags : Symbol(SymbolFlags, Decl(a.ts, 11, 8))
+
+=== /b.ts ===
+import type { SyntaxKind, SymbolFlags } from './a';
+>SyntaxKind : Symbol(SyntaxKind, Decl(b.ts, 0, 13))
+>SymbolFlags : Symbol(SymbolFlags, Decl(b.ts, 0, 25))
+
+SyntaxKind.ImportClause;
+SymbolFlags.Type;
+let kind: SyntaxKind.ImportClause;
+>kind : Symbol(kind, Decl(b.ts, 4, 3))
+>SyntaxKind : Symbol(SyntaxKind, Decl(b.ts, 0, 13))
+>ImportClause : Symbol(SyntaxKind.ImportClause)
+
+let flags: SymbolFlags;
+>flags : Symbol(flags, Decl(b.ts, 5, 3))
+>SymbolFlags : Symbol(SymbolFlags, Decl(b.ts, 0, 25))
+
+type TypeFlag = SymbolFlags.Type;
+>TypeFlag : Symbol(TypeFlag, Decl(b.ts, 5, 23))
+>SymbolFlags : Symbol(SymbolFlags, Decl(b.ts, 0, 25))
+>Type : Symbol(SymbolFlags.Type)
+
+export type { TypeFlag };
+>TypeFlag : Symbol(TypeFlag, Decl(b.ts, 8, 13))
+
+=== /c.ts ===
+import { SymbolFlags } from './a';
+>SymbolFlags : Symbol(SymbolFlags, Decl(c.ts, 0, 8))
+
+import type { TypeFlag } from './b';
+>TypeFlag : Symbol(TypeFlag, Decl(c.ts, 1, 13))
+
+const flags: TypeFlag = SymbolFlags.Type;
+>flags : Symbol(flags, Decl(c.ts, 2, 5))
+>TypeFlag : Symbol(TypeFlag, Decl(c.ts, 1, 13))
+>SymbolFlags.Type : Symbol(SymbolFlags.Type, Decl(a.ts, 5, 24))
+>SymbolFlags : Symbol(SymbolFlags, Decl(c.ts, 0, 8))
+>Type : Symbol(SymbolFlags.Type, Decl(a.ts, 5, 24))
+
diff --git a/tests/baselines/reference/enums.types b/tests/baselines/reference/enums.types
new file mode 100644
index 0000000000000..ca79cc6147d4a
--- /dev/null
+++ b/tests/baselines/reference/enums.types
@@ -0,0 +1,71 @@
+=== /a.ts ===
+enum SyntaxKind {
+>SyntaxKind : SyntaxKind
+
+  ImportClause,
+>ImportClause : SyntaxKind.ImportClause
+
+  ExportDeclaration
+>ExportDeclaration : SyntaxKind.ExportDeclaration
+}
+
+const enum SymbolFlags {
+>SymbolFlags : SymbolFlags
+
+  Type = "Type",
+>Type : SymbolFlags.Type
+>"Type" : "Type"
+
+  Value = "Value"
+>Value : SymbolFlags.Value
+>"Value" : "Value"
+}
+
+export type { SyntaxKind };
+>SyntaxKind : SyntaxKind
+
+export { SymbolFlags };
+>SymbolFlags : typeof SymbolFlags
+
+=== /b.ts ===
+import type { SyntaxKind, SymbolFlags } from './a';
+>SyntaxKind : SyntaxKind
+>SymbolFlags : import("/a").SymbolFlags
+
+SyntaxKind.ImportClause;
+>SyntaxKind.ImportClause : any
+>SyntaxKind : any
+>ImportClause : any
+
+SymbolFlags.Type;
+>SymbolFlags.Type : any
+>SymbolFlags : any
+>Type : any
+
+let kind: SyntaxKind.ImportClause;
+>kind : SyntaxKind.ImportClause
+>SyntaxKind : any
+
+let flags: SymbolFlags;
+>flags : import("/a").SymbolFlags
+
+type TypeFlag = SymbolFlags.Type;
+>TypeFlag : import("/a").SymbolFlags.Type
+>SymbolFlags : any
+
+export type { TypeFlag };
+>TypeFlag : import("/a").SymbolFlags.Type
+
+=== /c.ts ===
+import { SymbolFlags } from './a';
+>SymbolFlags : typeof SymbolFlags
+
+import type { TypeFlag } from './b';
+>TypeFlag : SymbolFlags.Type
+
+const flags: TypeFlag = SymbolFlags.Type;
+>flags : SymbolFlags.Type
+>SymbolFlags.Type : SymbolFlags.Type
+>SymbolFlags : typeof SymbolFlags
+>Type : SymbolFlags.Type
+
diff --git a/tests/baselines/reference/exportDeclaration.errors.txt b/tests/baselines/reference/exportDeclaration.errors.txt
new file mode 100644
index 0000000000000..387b348843945
--- /dev/null
+++ b/tests/baselines/reference/exportDeclaration.errors.txt
@@ -0,0 +1,14 @@
+/b.ts(3,5): error TS2693: 'A' only refers to a type, but is being used as a value here.
+
+
+==== /a.ts (0 errors) ====
+    class A {}
+    export type { A };
+    
+==== /b.ts (1 errors) ====
+    import { A } from './a';
+    declare const a: A;
+    new A();
+        ~
+!!! error TS2693: 'A' only refers to a type, but is being used as a value here.
+    
\ No newline at end of file
diff --git a/tests/baselines/reference/exportDeclaration.js b/tests/baselines/reference/exportDeclaration.js
new file mode 100644
index 0000000000000..2699093d1323d
--- /dev/null
+++ b/tests/baselines/reference/exportDeclaration.js
@@ -0,0 +1,24 @@
+//// [tests/cases/conformance/externalModules/typeOnly/exportDeclaration.ts] ////
+
+//// [a.ts]
+class A {}
+export type { A };
+
+//// [b.ts]
+import { A } from './a';
+declare const a: A;
+new A();
+
+
+//// [a.js]
+"use strict";
+exports.__esModule = true;
+var A = /** @class */ (function () {
+    function A() {
+    }
+    return A;
+}());
+//// [b.js]
+"use strict";
+exports.__esModule = true;
+new A();
diff --git a/tests/baselines/reference/exportDeclaration.symbols b/tests/baselines/reference/exportDeclaration.symbols
new file mode 100644
index 0000000000000..c35f92e71592e
--- /dev/null
+++ b/tests/baselines/reference/exportDeclaration.symbols
@@ -0,0 +1,17 @@
+=== /a.ts ===
+class A {}
+>A : Symbol(A, Decl(a.ts, 0, 0))
+
+export type { A };
+>A : Symbol(A, Decl(a.ts, 1, 13))
+
+=== /b.ts ===
+import { A } from './a';
+>A : Symbol(A, Decl(b.ts, 0, 8))
+
+declare const a: A;
+>a : Symbol(a, Decl(b.ts, 1, 13))
+>A : Symbol(A, Decl(b.ts, 0, 8))
+
+new A();
+
diff --git a/tests/baselines/reference/exportDeclaration.types b/tests/baselines/reference/exportDeclaration.types
new file mode 100644
index 0000000000000..277082b8586a8
--- /dev/null
+++ b/tests/baselines/reference/exportDeclaration.types
@@ -0,0 +1,18 @@
+=== /a.ts ===
+class A {}
+>A : A
+
+export type { A };
+>A : A
+
+=== /b.ts ===
+import { A } from './a';
+>A : any
+
+declare const a: A;
+>a : A
+
+new A();
+>new A() : any
+>A : any
+
diff --git a/tests/baselines/reference/exportDeclaration_missingBraces.errors.txt b/tests/baselines/reference/exportDeclaration_missingBraces.errors.txt
new file mode 100644
index 0000000000000..9e74a9eea8b78
--- /dev/null
+++ b/tests/baselines/reference/exportDeclaration_missingBraces.errors.txt
@@ -0,0 +1,57 @@
+tests/cases/conformance/externalModules/typeOnly/exportDeclaration_missingBraces.ts(1,6): error TS2567: Enum declarations can only merge with namespace or other enum declarations.
+tests/cases/conformance/externalModules/typeOnly/exportDeclaration_missingBraces.ts(6,7): error TS2300: Duplicate identifier 'Box'.
+tests/cases/conformance/externalModules/typeOnly/exportDeclaration_missingBraces.ts(8,11): error TS2300: Duplicate identifier 'Circle'.
+tests/cases/conformance/externalModules/typeOnly/exportDeclaration_missingBraces.ts(11,16): error TS1005: '=' expected.
+tests/cases/conformance/externalModules/typeOnly/exportDeclaration_missingBraces.ts(14,13): error TS2567: Enum declarations can only merge with namespace or other enum declarations.
+tests/cases/conformance/externalModules/typeOnly/exportDeclaration_missingBraces.ts(14,20): error TS1005: '=' expected.
+tests/cases/conformance/externalModules/typeOnly/exportDeclaration_missingBraces.ts(15,13): error TS2300: Duplicate identifier 'Box'.
+tests/cases/conformance/externalModules/typeOnly/exportDeclaration_missingBraces.ts(15,16): error TS1005: '=' expected.
+tests/cases/conformance/externalModules/typeOnly/exportDeclaration_missingBraces.ts(16,13): error TS2300: Duplicate identifier 'Circle'.
+tests/cases/conformance/externalModules/typeOnly/exportDeclaration_missingBraces.ts(16,19): error TS1005: '=' expected.
+tests/cases/conformance/externalModules/typeOnly/exportDeclaration_missingBraces.ts(17,15): error TS1005: '=' expected.
+
+
+==== tests/cases/conformance/externalModules/typeOnly/exportDeclaration_missingBraces.ts (11 errors) ====
+    enum Numbers {
+         ~~~~~~~
+!!! error TS2567: Enum declarations can only merge with namespace or other enum declarations.
+      One,
+      Two
+    }
+    
+    class Box<T> {}
+          ~~~
+!!! error TS2300: Duplicate identifier 'Box'.
+    
+    interface Circle {}
+              ~~~~~~
+!!! error TS2300: Duplicate identifier 'Circle'.
+    
+    namespace ns {
+      export type T; // Normal parse error because there is no other 'T'
+                   ~
+!!! error TS1005: '=' expected.
+    }
+    
+    export type Numbers;
+                ~~~~~~~
+!!! error TS2567: Enum declarations can only merge with namespace or other enum declarations.
+!!! related TS1369 tests/cases/conformance/externalModules/typeOnly/exportDeclaration_missingBraces.ts:14:13: Did you mean 'export type { Numbers }'?
+                       ~
+!!! error TS1005: '=' expected.
+    export type Box;
+                ~~~
+!!! error TS2300: Duplicate identifier 'Box'.
+!!! related TS1369 tests/cases/conformance/externalModules/typeOnly/exportDeclaration_missingBraces.ts:15:13: Did you mean 'export type { Box }'?
+                   ~
+!!! error TS1005: '=' expected.
+    export type Circle;
+                ~~~~~~
+!!! error TS2300: Duplicate identifier 'Circle'.
+!!! related TS1369 tests/cases/conformance/externalModules/typeOnly/exportDeclaration_missingBraces.ts:16:13: Did you mean 'export type { Circle }'?
+                      ~
+!!! error TS1005: '=' expected.
+    export type ns;
+                  ~
+!!! error TS1005: '=' expected.
+    
\ No newline at end of file
diff --git a/tests/baselines/reference/exportDeclaration_moduleSpecifier-isolatedModules.js b/tests/baselines/reference/exportDeclaration_moduleSpecifier-isolatedModules.js
new file mode 100644
index 0000000000000..2915e1f0eb8b7
--- /dev/null
+++ b/tests/baselines/reference/exportDeclaration_moduleSpecifier-isolatedModules.js
@@ -0,0 +1,15 @@
+//// [tests/cases/conformance/externalModules/typeOnly/exportDeclaration_moduleSpecifier-isolatedModules.ts] ////
+
+//// [a.ts]
+export type A = {};
+
+//// [b.ts]
+export type { A } from './a'; // should not error, but would without `type`
+
+
+//// [a.js]
+"use strict";
+exports.__esModule = true;
+//// [b.js]
+"use strict";
+exports.__esModule = true;
diff --git a/tests/baselines/reference/exportDeclaration_moduleSpecifier-isolatedModules.symbols b/tests/baselines/reference/exportDeclaration_moduleSpecifier-isolatedModules.symbols
new file mode 100644
index 0000000000000..17a4593a0e9bf
--- /dev/null
+++ b/tests/baselines/reference/exportDeclaration_moduleSpecifier-isolatedModules.symbols
@@ -0,0 +1,8 @@
+=== /a.ts ===
+export type A = {};
+>A : Symbol(A, Decl(a.ts, 0, 0))
+
+=== /b.ts ===
+export type { A } from './a'; // should not error, but would without `type`
+>A : Symbol(A, Decl(b.ts, 0, 13))
+
diff --git a/tests/baselines/reference/exportDeclaration_moduleSpecifier-isolatedModules.types b/tests/baselines/reference/exportDeclaration_moduleSpecifier-isolatedModules.types
new file mode 100644
index 0000000000000..78d90f12023c3
--- /dev/null
+++ b/tests/baselines/reference/exportDeclaration_moduleSpecifier-isolatedModules.types
@@ -0,0 +1,8 @@
+=== /a.ts ===
+export type A = {};
+>A : A
+
+=== /b.ts ===
+export type { A } from './a'; // should not error, but would without `type`
+>A : import("/a").A
+
diff --git a/tests/baselines/reference/exportDeclaration_moduleSpecifier.errors.txt b/tests/baselines/reference/exportDeclaration_moduleSpecifier.errors.txt
new file mode 100644
index 0000000000000..6ef18aad95986
--- /dev/null
+++ b/tests/baselines/reference/exportDeclaration_moduleSpecifier.errors.txt
@@ -0,0 +1,16 @@
+/c.ts(3,5): error TS2693: 'A' only refers to a type, but is being used as a value here.
+
+
+==== /a.ts (0 errors) ====
+    export class A {}
+    
+==== /b.ts (0 errors) ====
+    export type { A } from './a';
+    
+==== /c.ts (1 errors) ====
+    import { A } from './b';
+    declare const a: A;
+    new A();
+        ~
+!!! error TS2693: 'A' only refers to a type, but is being used as a value here.
+    
\ No newline at end of file
diff --git a/tests/baselines/reference/exportDeclaration_moduleSpecifier.js b/tests/baselines/reference/exportDeclaration_moduleSpecifier.js
new file mode 100644
index 0000000000000..edc093f700b89
--- /dev/null
+++ b/tests/baselines/reference/exportDeclaration_moduleSpecifier.js
@@ -0,0 +1,30 @@
+//// [tests/cases/conformance/externalModules/typeOnly/exportDeclaration_moduleSpecifier.ts] ////
+
+//// [a.ts]
+export class A {}
+
+//// [b.ts]
+export type { A } from './a';
+
+//// [c.ts]
+import { A } from './b';
+declare const a: A;
+new A();
+
+
+//// [a.js]
+"use strict";
+exports.__esModule = true;
+var A = /** @class */ (function () {
+    function A() {
+    }
+    return A;
+}());
+exports.A = A;
+//// [b.js]
+"use strict";
+exports.__esModule = true;
+//// [c.js]
+"use strict";
+exports.__esModule = true;
+new A();
diff --git a/tests/baselines/reference/exportDeclaration_moduleSpecifier.symbols b/tests/baselines/reference/exportDeclaration_moduleSpecifier.symbols
new file mode 100644
index 0000000000000..e4917cddc066d
--- /dev/null
+++ b/tests/baselines/reference/exportDeclaration_moduleSpecifier.symbols
@@ -0,0 +1,18 @@
+=== /a.ts ===
+export class A {}
+>A : Symbol(A, Decl(a.ts, 0, 0))
+
+=== /b.ts ===
+export type { A } from './a';
+>A : Symbol(A, Decl(b.ts, 0, 13))
+
+=== /c.ts ===
+import { A } from './b';
+>A : Symbol(A, Decl(c.ts, 0, 8))
+
+declare const a: A;
+>a : Symbol(a, Decl(c.ts, 1, 13))
+>A : Symbol(A, Decl(c.ts, 0, 8))
+
+new A();
+
diff --git a/tests/baselines/reference/exportDeclaration_moduleSpecifier.types b/tests/baselines/reference/exportDeclaration_moduleSpecifier.types
new file mode 100644
index 0000000000000..b870b2804f582
--- /dev/null
+++ b/tests/baselines/reference/exportDeclaration_moduleSpecifier.types
@@ -0,0 +1,19 @@
+=== /a.ts ===
+export class A {}
+>A : A
+
+=== /b.ts ===
+export type { A } from './a';
+>A : import("/a").A
+
+=== /c.ts ===
+import { A } from './b';
+>A : any
+
+declare const a: A;
+>a : import("/a").A
+
+new A();
+>new A() : any
+>A : any
+
diff --git a/tests/baselines/reference/exportDeclaration_value.errors.txt b/tests/baselines/reference/exportDeclaration_value.errors.txt
new file mode 100644
index 0000000000000..d759ad8c7c57b
--- /dev/null
+++ b/tests/baselines/reference/exportDeclaration_value.errors.txt
@@ -0,0 +1,18 @@
+/a.ts(2,15): error TS1361: Type-only export must reference a type, but 'A' is a value.
+/b.ts(1,15): error TS1361: Type-only export must reference a type, but 'AA' is a value.
+
+
+==== /a.ts (1 errors) ====
+    const A = {};
+    export type { A };
+                  ~
+!!! error TS1361: Type-only export must reference a type, but 'A' is a value.
+!!! related TS2728 /a.ts:1:7: 'A' is declared here.
+    export const AA = {};
+    
+==== /b.ts (1 errors) ====
+    export type { AA } from './a';
+                  ~~
+!!! error TS1361: Type-only export must reference a type, but 'AA' is a value.
+!!! related TS2728 /a.ts:3:14: 'AA' is declared here.
+    
\ No newline at end of file
diff --git a/tests/baselines/reference/exportDeclaration_value.js b/tests/baselines/reference/exportDeclaration_value.js
new file mode 100644
index 0000000000000..8abeef1a7b279
--- /dev/null
+++ b/tests/baselines/reference/exportDeclaration_value.js
@@ -0,0 +1,19 @@
+//// [tests/cases/conformance/externalModules/typeOnly/exportDeclaration_value.ts] ////
+
+//// [a.ts]
+const A = {};
+export type { A };
+export const AA = {};
+
+//// [b.ts]
+export type { AA } from './a';
+
+
+//// [a.js]
+"use strict";
+exports.__esModule = true;
+var A = {};
+exports.AA = {};
+//// [b.js]
+"use strict";
+exports.__esModule = true;
diff --git a/tests/baselines/reference/exportDeclaration_value.symbols b/tests/baselines/reference/exportDeclaration_value.symbols
new file mode 100644
index 0000000000000..505dba2c5591b
--- /dev/null
+++ b/tests/baselines/reference/exportDeclaration_value.symbols
@@ -0,0 +1,14 @@
+=== /a.ts ===
+const A = {};
+>A : Symbol(A, Decl(a.ts, 0, 5))
+
+export type { A };
+>A : Symbol(A, Decl(a.ts, 1, 13))
+
+export const AA = {};
+>AA : Symbol(AA, Decl(a.ts, 2, 12))
+
+=== /b.ts ===
+export type { AA } from './a';
+>AA : Symbol(AA, Decl(b.ts, 0, 13))
+
diff --git a/tests/baselines/reference/exportDeclaration_value.types b/tests/baselines/reference/exportDeclaration_value.types
new file mode 100644
index 0000000000000..524b6fd57fb21
--- /dev/null
+++ b/tests/baselines/reference/exportDeclaration_value.types
@@ -0,0 +1,16 @@
+=== /a.ts ===
+const A = {};
+>A : {}
+>{} : {}
+
+export type { A };
+>A : any
+
+export const AA = {};
+>AA : {}
+>{} : {}
+
+=== /b.ts ===
+export type { AA } from './a';
+>AA : any
+
diff --git a/tests/baselines/reference/filterNamespace_import.errors.txt b/tests/baselines/reference/filterNamespace_import.errors.txt
new file mode 100644
index 0000000000000..b9e9a09f8c790
--- /dev/null
+++ b/tests/baselines/reference/filterNamespace_import.errors.txt
@@ -0,0 +1,30 @@
+/a.ts(2,1): error TS2708: Cannot use namespace 'ns' as a value.
+/a.ts(3,1): error TS2708: Cannot use namespace 'ns' as a value.
+
+
+==== /ns.ts (0 errors) ====
+    namespace ns {
+      export type Type = string;
+      export class Class {}
+      export const Value = "";
+      export namespace nested {
+        export class NestedClass {
+          a!: string;
+        }
+      }
+    }
+    
+    export default ns;
+    
+==== /a.ts (2 errors) ====
+    import type ns from './ns';
+    ns.Class; // Error
+    ~~
+!!! error TS2708: Cannot use namespace 'ns' as a value.
+    ns.Value; // Error
+    ~~
+!!! error TS2708: Cannot use namespace 'ns' as a value.
+    let c: ns.Class;
+    let t: ns.Type = "";
+    let n: ns.nested.NestedClass = { a: '' };
+    
\ No newline at end of file
diff --git a/tests/baselines/reference/filterNamespace_import.js b/tests/baselines/reference/filterNamespace_import.js
new file mode 100644
index 0000000000000..094cabd326760
--- /dev/null
+++ b/tests/baselines/reference/filterNamespace_import.js
@@ -0,0 +1,56 @@
+//// [tests/cases/conformance/externalModules/typeOnly/filterNamespace_import.ts] ////
+
+//// [ns.ts]
+namespace ns {
+  export type Type = string;
+  export class Class {}
+  export const Value = "";
+  export namespace nested {
+    export class NestedClass {
+      a!: string;
+    }
+  }
+}
+
+export default ns;
+
+//// [a.ts]
+import type ns from './ns';
+ns.Class; // Error
+ns.Value; // Error
+let c: ns.Class;
+let t: ns.Type = "";
+let n: ns.nested.NestedClass = { a: '' };
+
+
+//// [ns.js]
+"use strict";
+exports.__esModule = true;
+var ns;
+(function (ns) {
+    var Class = /** @class */ (function () {
+        function Class() {
+        }
+        return Class;
+    }());
+    ns.Class = Class;
+    ns.Value = "";
+    var nested;
+    (function (nested) {
+        var NestedClass = /** @class */ (function () {
+            function NestedClass() {
+            }
+            return NestedClass;
+        }());
+        nested.NestedClass = NestedClass;
+    })(nested = ns.nested || (ns.nested = {}));
+})(ns || (ns = {}));
+exports["default"] = ns;
+//// [a.js]
+"use strict";
+exports.__esModule = true;
+ns.Class; // Error
+ns.Value; // Error
+var c;
+var t = "";
+var n = { a: '' };
diff --git a/tests/baselines/reference/filterNamespace_import.symbols b/tests/baselines/reference/filterNamespace_import.symbols
new file mode 100644
index 0000000000000..f38ea7cc983c9
--- /dev/null
+++ b/tests/baselines/reference/filterNamespace_import.symbols
@@ -0,0 +1,51 @@
+=== /ns.ts ===
+namespace ns {
+>ns : Symbol(ns, Decl(ns.ts, 0, 0))
+
+  export type Type = string;
+>Type : Symbol(Type, Decl(ns.ts, 0, 14))
+
+  export class Class {}
+>Class : Symbol(Class, Decl(ns.ts, 1, 28))
+
+  export const Value = "";
+>Value : Symbol(Value, Decl(ns.ts, 3, 14))
+
+  export namespace nested {
+>nested : Symbol(nested, Decl(ns.ts, 3, 26))
+
+    export class NestedClass {
+>NestedClass : Symbol(NestedClass, Decl(ns.ts, 4, 27))
+
+      a!: string;
+>a : Symbol(NestedClass.a, Decl(ns.ts, 5, 30))
+    }
+  }
+}
+
+export default ns;
+>ns : Symbol(ns, Decl(ns.ts, 0, 0))
+
+=== /a.ts ===
+import type ns from './ns';
+>ns : Symbol(ns, Decl(a.ts, 0, 6))
+
+ns.Class; // Error
+ns.Value; // Error
+let c: ns.Class;
+>c : Symbol(c, Decl(a.ts, 3, 3))
+>ns : Symbol(ns, Decl(a.ts, 0, 6))
+>Class : Symbol(ns.Class)
+
+let t: ns.Type = "";
+>t : Symbol(t, Decl(a.ts, 4, 3))
+>ns : Symbol(ns, Decl(a.ts, 0, 6))
+>Type : Symbol(ns.Type, Decl(ns.ts, 0, 14))
+
+let n: ns.nested.NestedClass = { a: '' };
+>n : Symbol(n, Decl(a.ts, 5, 3))
+>ns : Symbol(ns, Decl(a.ts, 0, 6))
+>nested : Symbol(ns.nested, Decl(ns.ts, 3, 26))
+>NestedClass : Symbol(NestedClass)
+>a : Symbol(a, Decl(a.ts, 5, 32))
+
diff --git a/tests/baselines/reference/filterNamespace_import.types b/tests/baselines/reference/filterNamespace_import.types
new file mode 100644
index 0000000000000..ef9ad8a6e269b
--- /dev/null
+++ b/tests/baselines/reference/filterNamespace_import.types
@@ -0,0 +1,60 @@
+=== /ns.ts ===
+namespace ns {
+>ns : typeof ns
+
+  export type Type = string;
+>Type : string
+
+  export class Class {}
+>Class : Class
+
+  export const Value = "";
+>Value : ""
+>"" : ""
+
+  export namespace nested {
+>nested : typeof nested
+
+    export class NestedClass {
+>NestedClass : NestedClass
+
+      a!: string;
+>a : string
+    }
+  }
+}
+
+export default ns;
+>ns : typeof ns
+
+=== /a.ts ===
+import type ns from './ns';
+>ns : any
+
+ns.Class; // Error
+>ns.Class : any
+>ns : any
+>Class : any
+
+ns.Value; // Error
+>ns.Value : any
+>ns : any
+>Value : any
+
+let c: ns.Class;
+>c : import("/ns").default.Class
+>ns : any
+
+let t: ns.Type = "";
+>t : string
+>ns : any
+>"" : ""
+
+let n: ns.nested.NestedClass = { a: '' };
+>n : import("/ns").default.nested.NestedClass
+>ns : any
+>nested : any
+>{ a: '' } : { a: string; }
+>a : string
+>'' : ""
+
diff --git a/tests/baselines/reference/generic.errors.txt b/tests/baselines/reference/generic.errors.txt
new file mode 100644
index 0000000000000..0b1c394dec78d
--- /dev/null
+++ b/tests/baselines/reference/generic.errors.txt
@@ -0,0 +1,20 @@
+/b.ts(5,5): error TS2741: Property 'a' is missing in type '{}' but required in type 'A<boolean>'.
+/b.ts(6,8): error TS2314: Generic type 'A<T>' requires 1 type argument(s).
+
+
+==== /a.ts (0 errors) ====
+    export class A<T> { a!: T }
+    export type { A as B };
+    
+==== /b.ts (2 errors) ====
+    import type { A } from './a';
+    import { B } from './a';
+    let a: A<string> = { a: "" };
+    let b: B<number> = { a: 3 };
+    let c: A<boolean> = {};
+        ~
+!!! error TS2741: Property 'a' is missing in type '{}' but required in type 'A<boolean>'.
+!!! related TS2728 /a.ts:1:21: 'a' is declared here.
+    let d: B = { a: "" };
+           ~
+!!! error TS2314: Generic type 'A<T>' requires 1 type argument(s).
\ No newline at end of file
diff --git a/tests/baselines/reference/generic.js b/tests/baselines/reference/generic.js
new file mode 100644
index 0000000000000..ba9093b688330
--- /dev/null
+++ b/tests/baselines/reference/generic.js
@@ -0,0 +1,30 @@
+//// [tests/cases/conformance/externalModules/typeOnly/generic.ts] ////
+
+//// [a.ts]
+export class A<T> { a!: T }
+export type { A as B };
+
+//// [b.ts]
+import type { A } from './a';
+import { B } from './a';
+let a: A<string> = { a: "" };
+let b: B<number> = { a: 3 };
+let c: A<boolean> = {};
+let d: B = { a: "" };
+
+//// [a.js]
+"use strict";
+exports.__esModule = true;
+var A = /** @class */ (function () {
+    function A() {
+    }
+    return A;
+}());
+exports.A = A;
+//// [b.js]
+"use strict";
+exports.__esModule = true;
+var a = { a: "" };
+var b = { a: 3 };
+var c = {};
+var d = { a: "" };
diff --git a/tests/baselines/reference/generic.symbols b/tests/baselines/reference/generic.symbols
new file mode 100644
index 0000000000000..88625de90732d
--- /dev/null
+++ b/tests/baselines/reference/generic.symbols
@@ -0,0 +1,37 @@
+=== /a.ts ===
+export class A<T> { a!: T }
+>A : Symbol(A, Decl(a.ts, 0, 0))
+>T : Symbol(T, Decl(a.ts, 0, 15))
+>a : Symbol(A.a, Decl(a.ts, 0, 19))
+>T : Symbol(T, Decl(a.ts, 0, 15))
+
+export type { A as B };
+>A : Symbol(A)
+>B : Symbol(B, Decl(a.ts, 1, 13))
+
+=== /b.ts ===
+import type { A } from './a';
+>A : Symbol(A, Decl(b.ts, 0, 13))
+
+import { B } from './a';
+>B : Symbol(B, Decl(b.ts, 1, 8))
+
+let a: A<string> = { a: "" };
+>a : Symbol(a, Decl(b.ts, 2, 3))
+>A : Symbol(A, Decl(b.ts, 0, 13))
+>a : Symbol(a, Decl(b.ts, 2, 20))
+
+let b: B<number> = { a: 3 };
+>b : Symbol(b, Decl(b.ts, 3, 3))
+>B : Symbol(B, Decl(b.ts, 1, 8))
+>a : Symbol(a, Decl(b.ts, 3, 20))
+
+let c: A<boolean> = {};
+>c : Symbol(c, Decl(b.ts, 4, 3))
+>A : Symbol(A, Decl(b.ts, 0, 13))
+
+let d: B = { a: "" };
+>d : Symbol(d, Decl(b.ts, 5, 3))
+>B : Symbol(B, Decl(b.ts, 1, 8))
+>a : Symbol(a, Decl(b.ts, 5, 12))
+
diff --git a/tests/baselines/reference/generic.types b/tests/baselines/reference/generic.types
new file mode 100644
index 0000000000000..abe6f1da4a0a5
--- /dev/null
+++ b/tests/baselines/reference/generic.types
@@ -0,0 +1,38 @@
+=== /a.ts ===
+export class A<T> { a!: T }
+>A : A<T>
+>a : T
+
+export type { A as B };
+>A : A<T>
+>B : A<T>
+
+=== /b.ts ===
+import type { A } from './a';
+>A : import("/a").A<T>
+
+import { B } from './a';
+>B : any
+
+let a: A<string> = { a: "" };
+>a : import("/a").A<string>
+>{ a: "" } : { a: string; }
+>a : string
+>"" : ""
+
+let b: B<number> = { a: 3 };
+>b : import("/a").A<number>
+>{ a: 3 } : { a: number; }
+>a : number
+>3 : 3
+
+let c: A<boolean> = {};
+>c : import("/a").A<boolean>
+>{} : {}
+
+let d: B = { a: "" };
+>d : any
+>{ a: "" } : { a: string; }
+>a : string
+>"" : ""
+
diff --git a/tests/baselines/reference/grammarErrors.errors.txt b/tests/baselines/reference/grammarErrors.errors.txt
new file mode 100644
index 0000000000000..ad9d7c9f859ff
--- /dev/null
+++ b/tests/baselines/reference/grammarErrors.errors.txt
@@ -0,0 +1,29 @@
+error TS5055: Cannot write file '/a.js' because it would overwrite input file.
+  Adding a tsconfig.json file will help organize projects that contain both TypeScript and JavaScript files. Learn more at https://aka.ms/tsconfig.
+error TS5056: Cannot write file '/a.js' because it would be overwritten by multiple input files.
+/a.js(1,1): error TS8006: 'import type' declarations can only be used in TypeScript files.
+/a.js(2,1): error TS8006: 'export type' declarations can only be used in TypeScript files.
+/b.ts(1,8): error TS1363: A type-only import can specify a default import or named bindings, but not both.
+
+
+!!! error TS5055: Cannot write file '/a.js' because it would overwrite input file.
+!!! error TS5055:   Adding a tsconfig.json file will help organize projects that contain both TypeScript and JavaScript files. Learn more at https://aka.ms/tsconfig.
+!!! error TS5056: Cannot write file '/a.js' because it would be overwritten by multiple input files.
+==== /a.ts (0 errors) ====
+    export default class A {}
+    export class B {}
+    export class C {}
+    
+==== /b.ts (1 errors) ====
+    import type A, { B, C } from './a';
+           ~~~~~~~~~~~~~~~~
+!!! error TS1363: A type-only import can specify a default import or named bindings, but not both.
+    
+==== /a.js (2 errors) ====
+    import type A from './a';
+    ~~~~~~~~~~~~~~~~~~~~~~~~~
+!!! error TS8006: 'import type' declarations can only be used in TypeScript files.
+    export type { A };
+    ~~~~~~~~~~~~~~~~~~
+!!! error TS8006: 'export type' declarations can only be used in TypeScript files.
+    
\ No newline at end of file
diff --git a/tests/baselines/reference/grammarErrors.js b/tests/baselines/reference/grammarErrors.js
new file mode 100644
index 0000000000000..bb1e4e1d1ec55
--- /dev/null
+++ b/tests/baselines/reference/grammarErrors.js
@@ -0,0 +1,18 @@
+//// [tests/cases/conformance/externalModules/typeOnly/grammarErrors.ts] ////
+
+//// [a.ts]
+export default class A {}
+export class B {}
+export class C {}
+
+//// [b.ts]
+import type A, { B, C } from './a';
+
+//// [a.js]
+import type A from './a';
+export type { A };
+
+
+//// [b.js]
+"use strict";
+exports.__esModule = true;
diff --git a/tests/baselines/reference/importClause_default.errors.txt b/tests/baselines/reference/importClause_default.errors.txt
new file mode 100644
index 0000000000000..99345c4102f4c
--- /dev/null
+++ b/tests/baselines/reference/importClause_default.errors.txt
@@ -0,0 +1,13 @@
+/b.ts(2,5): error TS2693: 'A' only refers to a type, but is being used as a value here.
+
+
+==== /a.ts (0 errors) ====
+    export default class A { a!: string }
+    
+==== /b.ts (1 errors) ====
+    import type A from './a';
+    new A();
+        ~
+!!! error TS2693: 'A' only refers to a type, but is being used as a value here.
+    let a: A = { a: '' };
+    
\ No newline at end of file
diff --git a/tests/baselines/reference/importClause_default.js b/tests/baselines/reference/importClause_default.js
new file mode 100644
index 0000000000000..d9e7c54331d4f
--- /dev/null
+++ b/tests/baselines/reference/importClause_default.js
@@ -0,0 +1,25 @@
+//// [tests/cases/conformance/externalModules/typeOnly/importClause_default.ts] ////
+
+//// [a.ts]
+export default class A { a!: string }
+
+//// [b.ts]
+import type A from './a';
+new A();
+let a: A = { a: '' };
+
+
+//// [a.js]
+"use strict";
+exports.__esModule = true;
+var A = /** @class */ (function () {
+    function A() {
+    }
+    return A;
+}());
+exports["default"] = A;
+//// [b.js]
+"use strict";
+exports.__esModule = true;
+new A();
+var a = { a: '' };
diff --git a/tests/baselines/reference/importClause_default.symbols b/tests/baselines/reference/importClause_default.symbols
new file mode 100644
index 0000000000000..3c13a061eaa23
--- /dev/null
+++ b/tests/baselines/reference/importClause_default.symbols
@@ -0,0 +1,15 @@
+=== /a.ts ===
+export default class A { a!: string }
+>A : Symbol(A, Decl(a.ts, 0, 0))
+>a : Symbol(A.a, Decl(a.ts, 0, 24))
+
+=== /b.ts ===
+import type A from './a';
+>A : Symbol(A, Decl(b.ts, 0, 6))
+
+new A();
+let a: A = { a: '' };
+>a : Symbol(a, Decl(b.ts, 2, 3))
+>A : Symbol(A, Decl(b.ts, 0, 6))
+>a : Symbol(a, Decl(b.ts, 2, 12))
+
diff --git a/tests/baselines/reference/importClause_default.types b/tests/baselines/reference/importClause_default.types
new file mode 100644
index 0000000000000..47ab1c72d607a
--- /dev/null
+++ b/tests/baselines/reference/importClause_default.types
@@ -0,0 +1,19 @@
+=== /a.ts ===
+export default class A { a!: string }
+>A : A
+>a : string
+
+=== /b.ts ===
+import type A from './a';
+>A : import("/a").default
+
+new A();
+>new A() : any
+>A : any
+
+let a: A = { a: '' };
+>a : import("/a").default
+>{ a: '' } : { a: string; }
+>a : string
+>'' : ""
+
diff --git a/tests/baselines/reference/importClause_namedImports.errors.txt b/tests/baselines/reference/importClause_namedImports.errors.txt
new file mode 100644
index 0000000000000..c5cc2bb326006
--- /dev/null
+++ b/tests/baselines/reference/importClause_namedImports.errors.txt
@@ -0,0 +1,21 @@
+/d.ts(1,21): error TS1361: Type-only import must reference a type, but 'C' is a value.
+/d.ts(2,5): error TS2693: 'A' only refers to a type, but is being used as a value here.
+
+
+==== /abc.ts (0 errors) ====
+    export class A {}
+    export type B  = { b: string };
+    export const C = "";
+    
+==== /d.ts (2 errors) ====
+    import type { A, B, C } from './abc';
+                        ~
+!!! error TS1361: Type-only import must reference a type, but 'C' is a value.
+!!! related TS2728 /abc.ts:3:14: 'C' is declared here.
+    new A();
+        ~
+!!! error TS2693: 'A' only refers to a type, but is being used as a value here.
+    declare let a: A;
+    declare let b: B;
+    b.b;
+    
\ No newline at end of file
diff --git a/tests/baselines/reference/importClause_namedImports.js b/tests/baselines/reference/importClause_namedImports.js
new file mode 100644
index 0000000000000..af9017f73130d
--- /dev/null
+++ b/tests/baselines/reference/importClause_namedImports.js
@@ -0,0 +1,30 @@
+//// [tests/cases/conformance/externalModules/typeOnly/importClause_namedImports.ts] ////
+
+//// [abc.ts]
+export class A {}
+export type B  = { b: string };
+export const C = "";
+
+//// [d.ts]
+import type { A, B, C } from './abc';
+new A();
+declare let a: A;
+declare let b: B;
+b.b;
+
+
+//// [abc.js]
+"use strict";
+exports.__esModule = true;
+var A = /** @class */ (function () {
+    function A() {
+    }
+    return A;
+}());
+exports.A = A;
+exports.C = "";
+//// [d.js]
+"use strict";
+exports.__esModule = true;
+new A();
+b.b;
diff --git a/tests/baselines/reference/importClause_namedImports.symbols b/tests/baselines/reference/importClause_namedImports.symbols
new file mode 100644
index 0000000000000..a21e8d8cba2bb
--- /dev/null
+++ b/tests/baselines/reference/importClause_namedImports.symbols
@@ -0,0 +1,31 @@
+=== /abc.ts ===
+export class A {}
+>A : Symbol(A, Decl(abc.ts, 0, 0))
+
+export type B  = { b: string };
+>B : Symbol(B, Decl(abc.ts, 0, 17))
+>b : Symbol(b, Decl(abc.ts, 1, 18))
+
+export const C = "";
+>C : Symbol(C, Decl(abc.ts, 2, 12))
+
+=== /d.ts ===
+import type { A, B, C } from './abc';
+>A : Symbol(A, Decl(d.ts, 0, 13))
+>B : Symbol(B, Decl(d.ts, 0, 16))
+>C : Symbol(C, Decl(d.ts, 0, 19))
+
+new A();
+declare let a: A;
+>a : Symbol(a, Decl(d.ts, 2, 11))
+>A : Symbol(A, Decl(d.ts, 0, 13))
+
+declare let b: B;
+>b : Symbol(b, Decl(d.ts, 3, 11))
+>B : Symbol(B, Decl(d.ts, 0, 16))
+
+b.b;
+>b.b : Symbol(b, Decl(abc.ts, 1, 18))
+>b : Symbol(b, Decl(d.ts, 3, 11))
+>b : Symbol(b, Decl(abc.ts, 1, 18))
+
diff --git a/tests/baselines/reference/importClause_namedImports.types b/tests/baselines/reference/importClause_namedImports.types
new file mode 100644
index 0000000000000..a9c43fcf582ad
--- /dev/null
+++ b/tests/baselines/reference/importClause_namedImports.types
@@ -0,0 +1,33 @@
+=== /abc.ts ===
+export class A {}
+>A : A
+
+export type B  = { b: string };
+>B : B
+>b : string
+
+export const C = "";
+>C : ""
+>"" : ""
+
+=== /d.ts ===
+import type { A, B, C } from './abc';
+>A : import("/abc").A
+>B : B
+>C : any
+
+new A();
+>new A() : any
+>A : any
+
+declare let a: A;
+>a : import("/abc").A
+
+declare let b: B;
+>b : B
+
+b.b;
+>b.b : string
+>b : B
+>b : string
+
diff --git a/tests/baselines/reference/importClause_namespaceImport.errors.txt b/tests/baselines/reference/importClause_namespaceImport.errors.txt
new file mode 100644
index 0000000000000..04d8dceddd02c
--- /dev/null
+++ b/tests/baselines/reference/importClause_namespaceImport.errors.txt
@@ -0,0 +1,34 @@
+/b.ts(2,1): error TS2708: Cannot use namespace 'types' as a value.
+/b.ts(3,1): error TS2708: Cannot use namespace 'types' as a value.
+/b.ts(4,14): error TS2694: Namespace '"/a"' has no exported member 'Value'.
+/b.ts(5,7): error TS2741: Property 'a' is missing in type '{}' but required in type 'A'.
+/b.ts(6,7): error TS2741: Property 'b' is missing in type '{}' but required in type 'B'.
+
+
+==== /a.ts (0 errors) ====
+    export class A { a!: string }
+    export class B { b!: number }
+    export type C<T> = T;
+    export const Value = {};
+    
+==== /b.ts (5 errors) ====
+    import type * as types from './a';
+    types;
+    ~~~~~
+!!! error TS2708: Cannot use namespace 'types' as a value.
+    types.Value;
+    ~~~~~
+!!! error TS2708: Cannot use namespace 'types' as a value.
+    let v: types.Value;
+                 ~~~~~
+!!! error TS2694: Namespace '"/a"' has no exported member 'Value'.
+    const a: types.A = {};
+          ~
+!!! error TS2741: Property 'a' is missing in type '{}' but required in type 'A'.
+!!! related TS2728 /a.ts:1:18: 'a' is declared here.
+    const b: types.B = {};
+          ~
+!!! error TS2741: Property 'b' is missing in type '{}' but required in type 'B'.
+!!! related TS2728 /a.ts:2:18: 'b' is declared here.
+    const c: types.C<string> = "";
+    
\ No newline at end of file
diff --git a/tests/baselines/reference/importClause_namespaceImport.js b/tests/baselines/reference/importClause_namespaceImport.js
new file mode 100644
index 0000000000000..4e1410e999d86
--- /dev/null
+++ b/tests/baselines/reference/importClause_namespaceImport.js
@@ -0,0 +1,43 @@
+//// [tests/cases/conformance/externalModules/typeOnly/importClause_namespaceImport.ts] ////
+
+//// [a.ts]
+export class A { a!: string }
+export class B { b!: number }
+export type C<T> = T;
+export const Value = {};
+
+//// [b.ts]
+import type * as types from './a';
+types;
+types.Value;
+let v: types.Value;
+const a: types.A = {};
+const b: types.B = {};
+const c: types.C<string> = "";
+
+
+//// [a.js]
+"use strict";
+exports.__esModule = true;
+var A = /** @class */ (function () {
+    function A() {
+    }
+    return A;
+}());
+exports.A = A;
+var B = /** @class */ (function () {
+    function B() {
+    }
+    return B;
+}());
+exports.B = B;
+exports.Value = {};
+//// [b.js]
+"use strict";
+exports.__esModule = true;
+types;
+types.Value;
+var v;
+var a = {};
+var b = {};
+var c = "";
diff --git a/tests/baselines/reference/importClause_namespaceImport.symbols b/tests/baselines/reference/importClause_namespaceImport.symbols
new file mode 100644
index 0000000000000..4242b05a4ca9d
--- /dev/null
+++ b/tests/baselines/reference/importClause_namespaceImport.symbols
@@ -0,0 +1,42 @@
+=== /a.ts ===
+export class A { a!: string }
+>A : Symbol(A, Decl(a.ts, 0, 0))
+>a : Symbol(A.a, Decl(a.ts, 0, 16))
+
+export class B { b!: number }
+>B : Symbol(B, Decl(a.ts, 0, 29))
+>b : Symbol(B.b, Decl(a.ts, 1, 16))
+
+export type C<T> = T;
+>C : Symbol(C, Decl(a.ts, 1, 29))
+>T : Symbol(T, Decl(a.ts, 2, 14))
+>T : Symbol(T, Decl(a.ts, 2, 14))
+
+export const Value = {};
+>Value : Symbol(Value, Decl(a.ts, 3, 12))
+
+=== /b.ts ===
+import type * as types from './a';
+>types : Symbol(types, Decl(b.ts, 0, 11))
+
+types;
+types.Value;
+let v: types.Value;
+>v : Symbol(v, Decl(b.ts, 3, 3))
+>types : Symbol(types, Decl(b.ts, 0, 11))
+
+const a: types.A = {};
+>a : Symbol(a, Decl(b.ts, 4, 5))
+>types : Symbol(types, Decl(b.ts, 0, 11))
+>A : Symbol(types.A)
+
+const b: types.B = {};
+>b : Symbol(b, Decl(b.ts, 5, 5))
+>types : Symbol(types, Decl(b.ts, 0, 11))
+>B : Symbol(types.B)
+
+const c: types.C<string> = "";
+>c : Symbol(c, Decl(b.ts, 6, 5))
+>types : Symbol(types, Decl(b.ts, 0, 11))
+>C : Symbol(types.C, Decl(a.ts, 1, 29))
+
diff --git a/tests/baselines/reference/importClause_namespaceImport.types b/tests/baselines/reference/importClause_namespaceImport.types
new file mode 100644
index 0000000000000..319edbd5632c3
--- /dev/null
+++ b/tests/baselines/reference/importClause_namespaceImport.types
@@ -0,0 +1,47 @@
+=== /a.ts ===
+export class A { a!: string }
+>A : A
+>a : string
+
+export class B { b!: number }
+>B : B
+>b : number
+
+export type C<T> = T;
+>C : T
+
+export const Value = {};
+>Value : {}
+>{} : {}
+
+=== /b.ts ===
+import type * as types from './a';
+>types : any
+
+types;
+>types : any
+
+types.Value;
+>types.Value : any
+>types : any
+>Value : any
+
+let v: types.Value;
+>v : any
+>types : any
+
+const a: types.A = {};
+>a : import("/a").A
+>types : any
+>{} : {}
+
+const b: types.B = {};
+>b : import("/a").B
+>types : any
+>{} : {}
+
+const c: types.C<string> = "";
+>c : string
+>types : any
+>"" : ""
+
diff --git a/tests/baselines/reference/importDefaultNamedType.js b/tests/baselines/reference/importDefaultNamedType.js
new file mode 100644
index 0000000000000..72f4f462ce4a5
--- /dev/null
+++ b/tests/baselines/reference/importDefaultNamedType.js
@@ -0,0 +1,21 @@
+//// [tests/cases/conformance/externalModules/typeOnly/importDefaultNamedType.ts] ////
+
+//// [a.ts]
+export default class A {}
+
+//// [b.ts]
+import type from './a';
+
+
+//// [a.js]
+"use strict";
+exports.__esModule = true;
+var A = /** @class */ (function () {
+    function A() {
+    }
+    return A;
+}());
+exports["default"] = A;
+//// [b.js]
+"use strict";
+exports.__esModule = true;
diff --git a/tests/baselines/reference/importDefaultNamedType.symbols b/tests/baselines/reference/importDefaultNamedType.symbols
new file mode 100644
index 0000000000000..c8c17d5584615
--- /dev/null
+++ b/tests/baselines/reference/importDefaultNamedType.symbols
@@ -0,0 +1,8 @@
+=== /a.ts ===
+export default class A {}
+>A : Symbol(A, Decl(a.ts, 0, 0))
+
+=== /b.ts ===
+import type from './a';
+>type : Symbol(type, Decl(b.ts, 0, 6))
+
diff --git a/tests/baselines/reference/importDefaultNamedType.types b/tests/baselines/reference/importDefaultNamedType.types
new file mode 100644
index 0000000000000..496fc7fe53334
--- /dev/null
+++ b/tests/baselines/reference/importDefaultNamedType.types
@@ -0,0 +1,8 @@
+=== /a.ts ===
+export default class A {}
+>A : A
+
+=== /b.ts ===
+import type from './a';
+>type : typeof type
+
diff --git a/tests/baselines/reference/importEqualsDeclarationError.errors.txt b/tests/baselines/reference/importEqualsDeclarationError.errors.txt
new file mode 100644
index 0000000000000..1d3f606b3e048
--- /dev/null
+++ b/tests/baselines/reference/importEqualsDeclarationError.errors.txt
@@ -0,0 +1,17 @@
+/c.ts(1,1): error TS1370: Only ECMAScript imports may use 'import type'.
+
+
+==== /c.ts (1 errors) ====
+    import type T = require('./a'); // Error
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+!!! error TS1370: Only ECMAScript imports may use 'import type'.
+    import type = require('./b');   // Ok
+    
+==== /a.ts (0 errors) ====
+    type T = {};
+    export = T;
+    
+==== /b.ts (0 errors) ====
+    class SomeClass {}
+    export = SomeClass;
+    
\ No newline at end of file
diff --git a/tests/baselines/reference/importsNotUsedAsValue_error.errors.txt b/tests/baselines/reference/importsNotUsedAsValue_error.errors.txt
new file mode 100644
index 0000000000000..6f6d8f6f3db7e
--- /dev/null
+++ b/tests/baselines/reference/importsNotUsedAsValue_error.errors.txt
@@ -0,0 +1,37 @@
+/b.ts(1,1): error TS1371: This import is never used as a value and must use 'import type' because the 'importsNotUsedAsValue' is set to 'error'.
+/c.ts(1,1): error TS1371: This import is never used as a value and must use 'import type' because the 'importsNotUsedAsValue' is set to 'error'.
+/e.ts(1,1): error TS6192: All imports in import declaration are unused.
+
+
+==== /a.ts (0 errors) ====
+    export default class {}
+    export class A {}
+    export type B = {};
+    
+==== /b.ts (1 errors) ====
+    import { A, B } from './a'; // Error
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+!!! error TS1371: This import is never used as a value and must use 'import type' because the 'importsNotUsedAsValue' is set to 'error'.
+    let a: A;
+    let b: B;
+    console.log(a, b);
+    
+==== /c.ts (1 errors) ====
+    import Default, * as named from './a'; // Error
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+!!! error TS1371: This import is never used as a value and must use 'import type' because the 'importsNotUsedAsValue' is set to 'error'.
+    let a: Default;
+    let b: named.B;
+    console.log(a, b);
+    
+==== /d.ts (0 errors) ====
+    import Default, { A } from './a';
+    const a = A;
+    let b: Default;
+    console.log(a, b);
+    
+==== /e.ts (1 errors) ====
+    import { A, B } from './a'; // noUnusedLocals error only
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+!!! error TS6192: All imports in import declaration are unused.
+    
\ No newline at end of file
diff --git a/tests/baselines/reference/importsNotUsedAsValue_error.js b/tests/baselines/reference/importsNotUsedAsValue_error.js
new file mode 100644
index 0000000000000..fe70b0dbe60a7
--- /dev/null
+++ b/tests/baselines/reference/importsNotUsedAsValue_error.js
@@ -0,0 +1,69 @@
+//// [tests/cases/conformance/externalModules/typeOnly/importsNotUsedAsValue_error.ts] ////
+
+//// [a.ts]
+export default class {}
+export class A {}
+export type B = {};
+
+//// [b.ts]
+import { A, B } from './a'; // Error
+let a: A;
+let b: B;
+console.log(a, b);
+
+//// [c.ts]
+import Default, * as named from './a'; // Error
+let a: Default;
+let b: named.B;
+console.log(a, b);
+
+//// [d.ts]
+import Default, { A } from './a';
+const a = A;
+let b: Default;
+console.log(a, b);
+
+//// [e.ts]
+import { A, B } from './a'; // noUnusedLocals error only
+
+
+//// [a.js]
+"use strict";
+exports.__esModule = true;
+var default_1 = /** @class */ (function () {
+    function default_1() {
+    }
+    return default_1;
+}());
+exports["default"] = default_1;
+var A = /** @class */ (function () {
+    function A() {
+    }
+    return A;
+}());
+exports.A = A;
+//// [b.js]
+"use strict";
+exports.__esModule = true;
+require("./a"); // Error
+var a;
+var b;
+console.log(a, b);
+//// [c.js]
+"use strict";
+exports.__esModule = true;
+require("./a"); // Error
+var a;
+var b;
+console.log(a, b);
+//// [d.js]
+"use strict";
+exports.__esModule = true;
+var a_1 = require("./a");
+var a = a_1.A;
+var b;
+console.log(a, b);
+//// [e.js]
+"use strict";
+exports.__esModule = true;
+require("./a"); // noUnusedLocals error only
diff --git a/tests/baselines/reference/importsNotUsedAsValue_error.symbols b/tests/baselines/reference/importsNotUsedAsValue_error.symbols
new file mode 100644
index 0000000000000..0726f61086fa5
--- /dev/null
+++ b/tests/baselines/reference/importsNotUsedAsValue_error.symbols
@@ -0,0 +1,74 @@
+=== /a.ts ===
+export default class {}
+export class A {}
+>A : Symbol(A, Decl(a.ts, 0, 23))
+
+export type B = {};
+>B : Symbol(B, Decl(a.ts, 1, 17))
+
+=== /b.ts ===
+import { A, B } from './a'; // Error
+>A : Symbol(A, Decl(b.ts, 0, 8))
+>B : Symbol(B, Decl(b.ts, 0, 11))
+
+let a: A;
+>a : Symbol(a, Decl(b.ts, 1, 3))
+>A : Symbol(A, Decl(b.ts, 0, 8))
+
+let b: B;
+>b : Symbol(b, Decl(b.ts, 2, 3))
+>B : Symbol(B, Decl(b.ts, 0, 11))
+
+console.log(a, b);
+>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
+>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
+>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
+>a : Symbol(a, Decl(b.ts, 1, 3))
+>b : Symbol(b, Decl(b.ts, 2, 3))
+
+=== /c.ts ===
+import Default, * as named from './a'; // Error
+>Default : Symbol(Default, Decl(c.ts, 0, 6))
+>named : Symbol(named, Decl(c.ts, 0, 15))
+
+let a: Default;
+>a : Symbol(a, Decl(c.ts, 1, 3))
+>Default : Symbol(Default, Decl(c.ts, 0, 6))
+
+let b: named.B;
+>b : Symbol(b, Decl(c.ts, 2, 3))
+>named : Symbol(named, Decl(c.ts, 0, 15))
+>B : Symbol(named.B, Decl(a.ts, 1, 17))
+
+console.log(a, b);
+>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
+>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
+>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
+>a : Symbol(a, Decl(c.ts, 1, 3))
+>b : Symbol(b, Decl(c.ts, 2, 3))
+
+=== /d.ts ===
+import Default, { A } from './a';
+>Default : Symbol(Default, Decl(d.ts, 0, 6))
+>A : Symbol(A, Decl(d.ts, 0, 17))
+
+const a = A;
+>a : Symbol(a, Decl(d.ts, 1, 5))
+>A : Symbol(A, Decl(d.ts, 0, 17))
+
+let b: Default;
+>b : Symbol(b, Decl(d.ts, 2, 3))
+>Default : Symbol(Default, Decl(d.ts, 0, 6))
+
+console.log(a, b);
+>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
+>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
+>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
+>a : Symbol(a, Decl(d.ts, 1, 5))
+>b : Symbol(b, Decl(d.ts, 2, 3))
+
+=== /e.ts ===
+import { A, B } from './a'; // noUnusedLocals error only
+>A : Symbol(A, Decl(e.ts, 0, 8))
+>B : Symbol(B, Decl(e.ts, 0, 11))
+
diff --git a/tests/baselines/reference/importsNotUsedAsValue_error.types b/tests/baselines/reference/importsNotUsedAsValue_error.types
new file mode 100644
index 0000000000000..5b166c47e684e
--- /dev/null
+++ b/tests/baselines/reference/importsNotUsedAsValue_error.types
@@ -0,0 +1,72 @@
+=== /a.ts ===
+export default class {}
+export class A {}
+>A : A
+
+export type B = {};
+>B : B
+
+=== /b.ts ===
+import { A, B } from './a'; // Error
+>A : typeof A
+>B : any
+
+let a: A;
+>a : A
+
+let b: B;
+>b : B
+
+console.log(a, b);
+>console.log(a, b) : void
+>console.log : (message?: any, ...optionalParams: any[]) => void
+>console : Console
+>log : (message?: any, ...optionalParams: any[]) => void
+>a : A
+>b : B
+
+=== /c.ts ===
+import Default, * as named from './a'; // Error
+>Default : typeof Default
+>named : typeof named
+
+let a: Default;
+>a : Default
+
+let b: named.B;
+>b : named.B
+>named : any
+
+console.log(a, b);
+>console.log(a, b) : void
+>console.log : (message?: any, ...optionalParams: any[]) => void
+>console : Console
+>log : (message?: any, ...optionalParams: any[]) => void
+>a : Default
+>b : named.B
+
+=== /d.ts ===
+import Default, { A } from './a';
+>Default : typeof Default
+>A : typeof A
+
+const a = A;
+>a : typeof A
+>A : typeof A
+
+let b: Default;
+>b : Default
+
+console.log(a, b);
+>console.log(a, b) : void
+>console.log : (message?: any, ...optionalParams: any[]) => void
+>console : Console
+>log : (message?: any, ...optionalParams: any[]) => void
+>a : typeof A
+>b : Default
+
+=== /e.ts ===
+import { A, B } from './a'; // noUnusedLocals error only
+>A : typeof A
+>B : any
+
diff --git a/tests/baselines/reference/isolatedModulesReExportType.errors.txt b/tests/baselines/reference/isolatedModulesReExportType.errors.txt
index dc035a84c2fc9..299bd0fcf88e6 100644
--- a/tests/baselines/reference/isolatedModulesReExportType.errors.txt
+++ b/tests/baselines/reference/isolatedModulesReExportType.errors.txt
@@ -1,12 +1,12 @@
-/user.ts(2,10): error TS1205: Cannot re-export a type when the '--isolatedModules' flag is provided.
-/user.ts(17,10): error TS1205: Cannot re-export a type when the '--isolatedModules' flag is provided.
+/user.ts(2,10): error TS1205: Re-exporting a type when the '--isolatedModules' flag is provided requires using 'export type'.
+/user.ts(17,10): error TS1205: Re-exporting a type when the '--isolatedModules' flag is provided requires using 'export type'.
 
 
 ==== /user.ts (2 errors) ====
     // Error, can't re-export something that's only a type.
     export { T } from "./exportT";
              ~
-!!! error TS1205: Cannot re-export a type when the '--isolatedModules' flag is provided.
+!!! error TS1205: Re-exporting a type when the '--isolatedModules' flag is provided requires using 'export type'.
     export import T2 = require("./exportEqualsT");
     
     // OK, has a value side
@@ -23,7 +23,7 @@
     import { T } from "./exportT";
     export { T as T4 };
              ~~~~~~~
-!!! error TS1205: Cannot re-export a type when the '--isolatedModules' flag is provided.
+!!! error TS1205: Re-exporting a type when the '--isolatedModules' flag is provided requires using 'export type'.
     
 ==== /exportT.ts (0 errors) ====
     export type T = number;
diff --git a/tests/baselines/reference/preserveUnusedImports.js b/tests/baselines/reference/preserveUnusedImports.js
new file mode 100644
index 0000000000000..7c2c089a72729
--- /dev/null
+++ b/tests/baselines/reference/preserveUnusedImports.js
@@ -0,0 +1,33 @@
+//// [tests/cases/compiler/preserveUnusedImports.ts] ////
+
+//// [a.ts]
+export type A = {};
+
+//// [b.ts]
+export class B {}
+
+//// [c.ts]
+import { A } from './a';
+import { B } from './b';
+
+let b: B;
+
+
+//// [a.js]
+"use strict";
+exports.__esModule = true;
+//// [b.js]
+"use strict";
+exports.__esModule = true;
+var B = /** @class */ (function () {
+    function B() {
+    }
+    return B;
+}());
+exports.B = B;
+//// [c.js]
+"use strict";
+exports.__esModule = true;
+require("./a");
+require("./b");
+var b;
diff --git a/tests/baselines/reference/preserveUnusedImports.symbols b/tests/baselines/reference/preserveUnusedImports.symbols
new file mode 100644
index 0000000000000..1b7189408eedd
--- /dev/null
+++ b/tests/baselines/reference/preserveUnusedImports.symbols
@@ -0,0 +1,19 @@
+=== tests/cases/compiler/a.ts ===
+export type A = {};
+>A : Symbol(A, Decl(a.ts, 0, 0))
+
+=== tests/cases/compiler/b.ts ===
+export class B {}
+>B : Symbol(B, Decl(b.ts, 0, 0))
+
+=== tests/cases/compiler/c.ts ===
+import { A } from './a';
+>A : Symbol(A, Decl(c.ts, 0, 8))
+
+import { B } from './b';
+>B : Symbol(B, Decl(c.ts, 1, 8))
+
+let b: B;
+>b : Symbol(b, Decl(c.ts, 3, 3))
+>B : Symbol(B, Decl(c.ts, 1, 8))
+
diff --git a/tests/baselines/reference/preserveUnusedImports.types b/tests/baselines/reference/preserveUnusedImports.types
new file mode 100644
index 0000000000000..e4e32ebb27ebb
--- /dev/null
+++ b/tests/baselines/reference/preserveUnusedImports.types
@@ -0,0 +1,18 @@
+=== tests/cases/compiler/a.ts ===
+export type A = {};
+>A : A
+
+=== tests/cases/compiler/b.ts ===
+export class B {}
+>B : B
+
+=== tests/cases/compiler/c.ts ===
+import { A } from './a';
+>A : any
+
+import { B } from './b';
+>B : typeof B
+
+let b: B;
+>b : B
+
diff --git a/tests/baselines/reference/renamed.errors.txt b/tests/baselines/reference/renamed.errors.txt
new file mode 100644
index 0000000000000..8f75a47757714
--- /dev/null
+++ b/tests/baselines/reference/renamed.errors.txt
@@ -0,0 +1,17 @@
+/c.ts(2,7): error TS2741: Property 'a' is missing in type '{}' but required in type 'A'.
+
+
+==== /a.ts (0 errors) ====
+    class A { a!: string }
+    export type { A as B };
+    
+==== /b.ts (0 errors) ====
+    export type { B as C } from './a';
+    
+==== /c.ts (1 errors) ====
+    import type { C as D } from './b';
+    const d: D = {};
+          ~
+!!! error TS2741: Property 'a' is missing in type '{}' but required in type 'A'.
+!!! related TS2728 /a.ts:1:11: 'a' is declared here.
+    
\ No newline at end of file
diff --git a/tests/baselines/reference/renamed.js b/tests/baselines/reference/renamed.js
new file mode 100644
index 0000000000000..b4e539bacb721
--- /dev/null
+++ b/tests/baselines/reference/renamed.js
@@ -0,0 +1,29 @@
+//// [tests/cases/conformance/externalModules/typeOnly/renamed.ts] ////
+
+//// [a.ts]
+class A { a!: string }
+export type { A as B };
+
+//// [b.ts]
+export type { B as C } from './a';
+
+//// [c.ts]
+import type { C as D } from './b';
+const d: D = {};
+
+
+//// [a.js]
+"use strict";
+exports.__esModule = true;
+var A = /** @class */ (function () {
+    function A() {
+    }
+    return A;
+}());
+//// [b.js]
+"use strict";
+exports.__esModule = true;
+//// [c.js]
+"use strict";
+exports.__esModule = true;
+var d = {};
diff --git a/tests/baselines/reference/renamed.symbols b/tests/baselines/reference/renamed.symbols
new file mode 100644
index 0000000000000..8af253a8c0370
--- /dev/null
+++ b/tests/baselines/reference/renamed.symbols
@@ -0,0 +1,23 @@
+=== /a.ts ===
+class A { a!: string }
+>A : Symbol(A, Decl(a.ts, 0, 0))
+>a : Symbol(A.a, Decl(a.ts, 0, 9))
+
+export type { A as B };
+>A : Symbol(A)
+>B : Symbol(B, Decl(a.ts, 1, 13))
+
+=== /b.ts ===
+export type { B as C } from './a';
+>B : Symbol(B, Decl(a.ts, 1, 13))
+>C : Symbol(C, Decl(b.ts, 0, 13))
+
+=== /c.ts ===
+import type { C as D } from './b';
+>C : Symbol(C, Decl(b.ts, 0, 13))
+>D : Symbol(D, Decl(c.ts, 0, 13))
+
+const d: D = {};
+>d : Symbol(d, Decl(c.ts, 1, 5))
+>D : Symbol(D, Decl(c.ts, 0, 13))
+
diff --git a/tests/baselines/reference/renamed.types b/tests/baselines/reference/renamed.types
new file mode 100644
index 0000000000000..85a9bfcc4002c
--- /dev/null
+++ b/tests/baselines/reference/renamed.types
@@ -0,0 +1,23 @@
+=== /a.ts ===
+class A { a!: string }
+>A : A
+>a : string
+
+export type { A as B };
+>A : A
+>B : A
+
+=== /b.ts ===
+export type { B as C } from './a';
+>B : A
+>C : A
+
+=== /c.ts ===
+import type { C as D } from './b';
+>C : A
+>D : A
+
+const d: D = {};
+>d : A
+>{} : {}
+
diff --git a/tests/baselines/reference/showConfig/Shows tsconfig for single option/importsNotUsedAsValue/tsconfig.json b/tests/baselines/reference/showConfig/Shows tsconfig for single option/importsNotUsedAsValue/tsconfig.json
new file mode 100644
index 0000000000000..f94214e3e9e58
--- /dev/null
+++ b/tests/baselines/reference/showConfig/Shows tsconfig for single option/importsNotUsedAsValue/tsconfig.json	
@@ -0,0 +1,5 @@
+{
+    "compilerOptions": {
+        "importsNotUsedAsValue": "remove"
+    }
+}
diff --git a/tests/baselines/reference/topLevelAwait(module=esnext,target=es2015).errors.txt b/tests/baselines/reference/topLevelAwait(module=esnext,target=es2015).errors.txt
index 9efe0c2aa612f..0bd384b85206d 100644
--- a/tests/baselines/reference/topLevelAwait(module=esnext,target=es2015).errors.txt
+++ b/tests/baselines/reference/topLevelAwait(module=esnext,target=es2015).errors.txt
@@ -1,9 +1,9 @@
-tests/cases/conformance/externalModules/topLevelAwait.ts(2,1): error TS1361: 'await' outside of an async function is only allowed at the top level of a module when '--module' is 'esnext' or 'system' and '--target' is 'es2017' or higher.
+tests/cases/conformance/externalModules/topLevelAwait.ts(2,1): error TS1375: 'await' outside of an async function is only allowed at the top level of a module when '--module' is 'esnext' or 'system' and '--target' is 'es2017' or higher.
 
 
 ==== tests/cases/conformance/externalModules/topLevelAwait.ts (1 errors) ====
     export const x = 1;
     await x;
     ~~~~~
-!!! error TS1361: 'await' outside of an async function is only allowed at the top level of a module when '--module' is 'esnext' or 'system' and '--target' is 'es2017' or higher.
+!!! error TS1375: 'await' outside of an async function is only allowed at the top level of a module when '--module' is 'esnext' or 'system' and '--target' is 'es2017' or higher.
     
\ No newline at end of file
diff --git a/tests/baselines/reference/topLevelAwait(module=system,target=es2015).errors.txt b/tests/baselines/reference/topLevelAwait(module=system,target=es2015).errors.txt
index 9efe0c2aa612f..0bd384b85206d 100644
--- a/tests/baselines/reference/topLevelAwait(module=system,target=es2015).errors.txt
+++ b/tests/baselines/reference/topLevelAwait(module=system,target=es2015).errors.txt
@@ -1,9 +1,9 @@
-tests/cases/conformance/externalModules/topLevelAwait.ts(2,1): error TS1361: 'await' outside of an async function is only allowed at the top level of a module when '--module' is 'esnext' or 'system' and '--target' is 'es2017' or higher.
+tests/cases/conformance/externalModules/topLevelAwait.ts(2,1): error TS1375: 'await' outside of an async function is only allowed at the top level of a module when '--module' is 'esnext' or 'system' and '--target' is 'es2017' or higher.
 
 
 ==== tests/cases/conformance/externalModules/topLevelAwait.ts (1 errors) ====
     export const x = 1;
     await x;
     ~~~~~
-!!! error TS1361: 'await' outside of an async function is only allowed at the top level of a module when '--module' is 'esnext' or 'system' and '--target' is 'es2017' or higher.
+!!! error TS1375: 'await' outside of an async function is only allowed at the top level of a module when '--module' is 'esnext' or 'system' and '--target' is 'es2017' or higher.
     
\ No newline at end of file
diff --git a/tests/baselines/reference/topLevelAwaitNonModule.errors.txt b/tests/baselines/reference/topLevelAwaitNonModule.errors.txt
index 8e2d3a6eab3cd..888c565e7a9d5 100644
--- a/tests/baselines/reference/topLevelAwaitNonModule.errors.txt
+++ b/tests/baselines/reference/topLevelAwaitNonModule.errors.txt
@@ -1,11 +1,11 @@
-tests/cases/conformance/externalModules/topLevelAwaitNonModule.ts(1,1): error TS1361: 'await' outside of an async function is only allowed at the top level of a module when '--module' is 'esnext' or 'system' and '--target' is 'es2017' or higher.
+tests/cases/conformance/externalModules/topLevelAwaitNonModule.ts(1,1): error TS1375: 'await' outside of an async function is only allowed at the top level of a module when '--module' is 'esnext' or 'system' and '--target' is 'es2017' or higher.
 tests/cases/conformance/externalModules/topLevelAwaitNonModule.ts(1,7): error TS2304: Cannot find name 'x'.
 
 
 ==== tests/cases/conformance/externalModules/topLevelAwaitNonModule.ts (2 errors) ====
     await x;
     ~~~~~
-!!! error TS1361: 'await' outside of an async function is only allowed at the top level of a module when '--module' is 'esnext' or 'system' and '--target' is 'es2017' or higher.
+!!! error TS1375: 'await' outside of an async function is only allowed at the top level of a module when '--module' is 'esnext' or 'system' and '--target' is 'es2017' or higher.
           ~
 !!! error TS2304: Cannot find name 'x'.
     
\ No newline at end of file
diff --git a/tests/cases/compiler/preserveUnusedImports.ts b/tests/cases/compiler/preserveUnusedImports.ts
new file mode 100644
index 0000000000000..e6d4497ef1592
--- /dev/null
+++ b/tests/cases/compiler/preserveUnusedImports.ts
@@ -0,0 +1,13 @@
+// @importsNotUsedAsValue: preserve
+
+// @Filename: a.ts
+export type A = {};
+
+// @Filename: b.ts
+export class B {}
+
+// @Filename: c.ts
+import { A } from './a';
+import { B } from './b';
+
+let b: B;
diff --git a/tests/cases/conformance/externalModules/typeOnly/chained.ts b/tests/cases/conformance/externalModules/typeOnly/chained.ts
new file mode 100644
index 0000000000000..57a0faad738aa
--- /dev/null
+++ b/tests/cases/conformance/externalModules/typeOnly/chained.ts
@@ -0,0 +1,17 @@
+// @Filename: /a.ts
+class A { a!: string }
+export type { A as B };
+export type Z = A;
+
+// @Filename: /b.ts
+import { Z as Y } from './a';
+export { B as C } from './a';
+
+// @Filename: /c.ts
+import type { C } from './b';
+export { C as D };
+
+// @Filename: /d.ts
+import { D } from './c';
+new D();
+const d: D = {};
diff --git a/tests/cases/conformance/externalModules/typeOnly/circular1.ts b/tests/cases/conformance/externalModules/typeOnly/circular1.ts
new file mode 100644
index 0000000000000..51fe382040e3e
--- /dev/null
+++ b/tests/cases/conformance/externalModules/typeOnly/circular1.ts
@@ -0,0 +1,7 @@
+// @noEmit: true
+
+// @Filename: /a.ts
+export type { A } from './b';
+
+// @Filename: /b.ts
+export type { A } from './a';
diff --git a/tests/cases/conformance/externalModules/typeOnly/circular2.ts b/tests/cases/conformance/externalModules/typeOnly/circular2.ts
new file mode 100644
index 0000000000000..a11f0a48fe0a7
--- /dev/null
+++ b/tests/cases/conformance/externalModules/typeOnly/circular2.ts
@@ -0,0 +1,9 @@
+// @noEmit: true
+
+// @Filename: /a.ts
+import type { B } from './b';
+export type A = B;
+
+// @Filename: /b.ts
+import type { A } from './a';
+export type B = A;
diff --git a/tests/cases/conformance/externalModules/typeOnly/circular3.ts b/tests/cases/conformance/externalModules/typeOnly/circular3.ts
new file mode 100644
index 0000000000000..0cd40f250098c
--- /dev/null
+++ b/tests/cases/conformance/externalModules/typeOnly/circular3.ts
@@ -0,0 +1,9 @@
+// @noEmit: true
+
+// @Filename: /a.ts
+import type { A } from './b';
+export type { A as B };
+
+// @Filename: /b.ts
+import type { B } from './a';
+export type { B as A };
diff --git a/tests/cases/conformance/externalModules/typeOnly/circular4.ts b/tests/cases/conformance/externalModules/typeOnly/circular4.ts
new file mode 100644
index 0000000000000..5dab72f03cf69
--- /dev/null
+++ b/tests/cases/conformance/externalModules/typeOnly/circular4.ts
@@ -0,0 +1,17 @@
+// @noEmit: true
+
+// @Filename: /a.ts
+import type { ns2 } from './b';
+export namespace ns1 {
+  export namespace nested {
+    export type T = ns2.nested.T;
+  }
+}
+
+// @Filename: /b.ts
+import type { ns1 } from './a';
+export namespace ns2 {
+  export namespace nested {
+    export type T = ns1.nested.T;
+  }
+}
diff --git a/tests/cases/conformance/externalModules/typeOnly/enums.ts b/tests/cases/conformance/externalModules/typeOnly/enums.ts
new file mode 100644
index 0000000000000..b632bdbce546b
--- /dev/null
+++ b/tests/cases/conformance/externalModules/typeOnly/enums.ts
@@ -0,0 +1,29 @@
+// @Filename: /a.ts
+enum SyntaxKind {
+  ImportClause,
+  ExportDeclaration
+}
+
+const enum SymbolFlags {
+  Type = "Type",
+  Value = "Value"
+}
+
+export type { SyntaxKind };
+export { SymbolFlags };
+
+// @Filename: /b.ts
+import type { SyntaxKind, SymbolFlags } from './a';
+
+SyntaxKind.ImportClause;
+SymbolFlags.Type;
+let kind: SyntaxKind.ImportClause;
+let flags: SymbolFlags;
+
+type TypeFlag = SymbolFlags.Type;
+export type { TypeFlag };
+
+// @Filename: /c.ts
+import { SymbolFlags } from './a';
+import type { TypeFlag } from './b';
+const flags: TypeFlag = SymbolFlags.Type;
diff --git a/tests/cases/conformance/externalModules/typeOnly/exportDeclaration.ts b/tests/cases/conformance/externalModules/typeOnly/exportDeclaration.ts
new file mode 100644
index 0000000000000..d492ece20901d
--- /dev/null
+++ b/tests/cases/conformance/externalModules/typeOnly/exportDeclaration.ts
@@ -0,0 +1,8 @@
+// @Filename: /a.ts
+class A {}
+export type { A };
+
+// @Filename: /b.ts
+import { A } from './a';
+declare const a: A;
+new A();
diff --git a/tests/cases/conformance/externalModules/typeOnly/exportDeclaration_missingBraces.ts b/tests/cases/conformance/externalModules/typeOnly/exportDeclaration_missingBraces.ts
new file mode 100644
index 0000000000000..e46cd4a69812f
--- /dev/null
+++ b/tests/cases/conformance/externalModules/typeOnly/exportDeclaration_missingBraces.ts
@@ -0,0 +1,20 @@
+// @noEmit: true
+// @noTypesAndSymbols: true
+
+enum Numbers {
+  One,
+  Two
+}
+
+class Box<T> {}
+
+interface Circle {}
+
+namespace ns {
+  export type T; // Normal parse error because there is no other 'T'
+}
+
+export type Numbers;
+export type Box;
+export type Circle;
+export type ns;
diff --git a/tests/cases/conformance/externalModules/typeOnly/exportDeclaration_moduleSpecifier-isolatedModules.ts b/tests/cases/conformance/externalModules/typeOnly/exportDeclaration_moduleSpecifier-isolatedModules.ts
new file mode 100644
index 0000000000000..e625e9065a0fc
--- /dev/null
+++ b/tests/cases/conformance/externalModules/typeOnly/exportDeclaration_moduleSpecifier-isolatedModules.ts
@@ -0,0 +1,7 @@
+// @isolatedModules: true
+
+// @Filename: /a.ts
+export type A = {};
+
+// @Filename: /b.ts
+export type { A } from './a'; // should not error, but would without `type`
diff --git a/tests/cases/conformance/externalModules/typeOnly/exportDeclaration_moduleSpecifier.ts b/tests/cases/conformance/externalModules/typeOnly/exportDeclaration_moduleSpecifier.ts
new file mode 100644
index 0000000000000..d33b6fe990047
--- /dev/null
+++ b/tests/cases/conformance/externalModules/typeOnly/exportDeclaration_moduleSpecifier.ts
@@ -0,0 +1,10 @@
+// @Filename: /a.ts
+export class A {}
+
+// @Filename: /b.ts
+export type { A } from './a';
+
+// @Filename: /c.ts
+import { A } from './b';
+declare const a: A;
+new A();
diff --git a/tests/cases/conformance/externalModules/typeOnly/exportDeclaration_value.ts b/tests/cases/conformance/externalModules/typeOnly/exportDeclaration_value.ts
new file mode 100644
index 0000000000000..1ae4c63b31049
--- /dev/null
+++ b/tests/cases/conformance/externalModules/typeOnly/exportDeclaration_value.ts
@@ -0,0 +1,7 @@
+// @Filename: /a.ts
+const A = {};
+export type { A };
+export const AA = {};
+
+// @Filename: /b.ts
+export type { AA } from './a';
diff --git a/tests/cases/conformance/externalModules/typeOnly/filterNamespace_import.ts b/tests/cases/conformance/externalModules/typeOnly/filterNamespace_import.ts
new file mode 100644
index 0000000000000..b0cd26e0a8a6c
--- /dev/null
+++ b/tests/cases/conformance/externalModules/typeOnly/filterNamespace_import.ts
@@ -0,0 +1,21 @@
+// @Filename: /ns.ts
+namespace ns {
+  export type Type = string;
+  export class Class {}
+  export const Value = "";
+  export namespace nested {
+    export class NestedClass {
+      a!: string;
+    }
+  }
+}
+
+export default ns;
+
+// @Filename: /a.ts
+import type ns from './ns';
+ns.Class; // Error
+ns.Value; // Error
+let c: ns.Class;
+let t: ns.Type = "";
+let n: ns.nested.NestedClass = { a: '' };
diff --git a/tests/cases/conformance/externalModules/typeOnly/generic.ts b/tests/cases/conformance/externalModules/typeOnly/generic.ts
new file mode 100644
index 0000000000000..5ea17492f1b8f
--- /dev/null
+++ b/tests/cases/conformance/externalModules/typeOnly/generic.ts
@@ -0,0 +1,11 @@
+// @Filename: /a.ts
+export class A<T> { a!: T }
+export type { A as B };
+
+// @Filename: /b.ts
+import type { A } from './a';
+import { B } from './a';
+let a: A<string> = { a: "" };
+let b: B<number> = { a: 3 };
+let c: A<boolean> = {};
+let d: B = { a: "" };
\ No newline at end of file
diff --git a/tests/cases/conformance/externalModules/typeOnly/grammarErrors.ts b/tests/cases/conformance/externalModules/typeOnly/grammarErrors.ts
new file mode 100644
index 0000000000000..e16efa45f9115
--- /dev/null
+++ b/tests/cases/conformance/externalModules/typeOnly/grammarErrors.ts
@@ -0,0 +1,15 @@
+// @noTypesAndSymbols: true
+// @allowJs: true
+// @checkJs: true
+
+// @Filename: /a.ts
+export default class A {}
+export class B {}
+export class C {}
+
+// @Filename: /b.ts
+import type A, { B, C } from './a';
+
+// @Filename: /a.js
+import type A from './a';
+export type { A };
diff --git a/tests/cases/conformance/externalModules/typeOnly/importClause_default.ts b/tests/cases/conformance/externalModules/typeOnly/importClause_default.ts
new file mode 100644
index 0000000000000..b3f5a5259e4cf
--- /dev/null
+++ b/tests/cases/conformance/externalModules/typeOnly/importClause_default.ts
@@ -0,0 +1,7 @@
+// @Filename: /a.ts
+export default class A { a!: string }
+
+// @Filename: /b.ts
+import type A from './a';
+new A();
+let a: A = { a: '' };
diff --git a/tests/cases/conformance/externalModules/typeOnly/importClause_namedImports.ts b/tests/cases/conformance/externalModules/typeOnly/importClause_namedImports.ts
new file mode 100644
index 0000000000000..c2642701a35ec
--- /dev/null
+++ b/tests/cases/conformance/externalModules/typeOnly/importClause_namedImports.ts
@@ -0,0 +1,11 @@
+// @Filename: /abc.ts
+export class A {}
+export type B  = { b: string };
+export const C = "";
+
+// @Filename: /d.ts
+import type { A, B, C } from './abc';
+new A();
+declare let a: A;
+declare let b: B;
+b.b;
diff --git a/tests/cases/conformance/externalModules/typeOnly/importClause_namespaceImport.ts b/tests/cases/conformance/externalModules/typeOnly/importClause_namespaceImport.ts
new file mode 100644
index 0000000000000..d9a6313c4d1c2
--- /dev/null
+++ b/tests/cases/conformance/externalModules/typeOnly/importClause_namespaceImport.ts
@@ -0,0 +1,14 @@
+// @Filename: /a.ts
+export class A { a!: string }
+export class B { b!: number }
+export type C<T> = T;
+export const Value = {};
+
+// @Filename: /b.ts
+import type * as types from './a';
+types;
+types.Value;
+let v: types.Value;
+const a: types.A = {};
+const b: types.B = {};
+const c: types.C<string> = "";
diff --git a/tests/cases/conformance/externalModules/typeOnly/importDefaultNamedType.ts b/tests/cases/conformance/externalModules/typeOnly/importDefaultNamedType.ts
new file mode 100644
index 0000000000000..507ad447710d4
--- /dev/null
+++ b/tests/cases/conformance/externalModules/typeOnly/importDefaultNamedType.ts
@@ -0,0 +1,5 @@
+// @Filename: /a.ts
+export default class A {}
+
+// @Filename: /b.ts
+import type from './a';
diff --git a/tests/cases/conformance/externalModules/typeOnly/importEqualsDeclarationError.ts b/tests/cases/conformance/externalModules/typeOnly/importEqualsDeclarationError.ts
new file mode 100644
index 0000000000000..f3b40cd48dca0
--- /dev/null
+++ b/tests/cases/conformance/externalModules/typeOnly/importEqualsDeclarationError.ts
@@ -0,0 +1,14 @@
+// @noEmit: true
+// @noTypesAndSymbols: true
+
+// @Filename: /a.ts
+type T = {};
+export = T;
+
+// @Filename: /b.ts
+class SomeClass {}
+export = SomeClass;
+
+// @Filename: /c.ts
+import type T = require('./a'); // Error
+import type = require('./b');   // Ok
diff --git a/tests/cases/conformance/externalModules/typeOnly/importsNotUsedAsValue_error.ts b/tests/cases/conformance/externalModules/typeOnly/importsNotUsedAsValue_error.ts
new file mode 100644
index 0000000000000..c74dfe8195167
--- /dev/null
+++ b/tests/cases/conformance/externalModules/typeOnly/importsNotUsedAsValue_error.ts
@@ -0,0 +1,28 @@
+// @importsNotUsedAsValue: error
+// @noUnusedLocals: true
+
+// @Filename: /a.ts
+export default class {}
+export class A {}
+export type B = {};
+
+// @Filename: /b.ts
+import { A, B } from './a'; // Error
+let a: A;
+let b: B;
+console.log(a, b);
+
+// @Filename: /c.ts
+import Default, * as named from './a'; // Error
+let a: Default;
+let b: named.B;
+console.log(a, b);
+
+// @Filename: /d.ts
+import Default, { A } from './a';
+const a = A;
+let b: Default;
+console.log(a, b);
+
+// @Filename: /e.ts
+import { A, B } from './a'; // noUnusedLocals error only
diff --git a/tests/cases/conformance/externalModules/typeOnly/renamed.ts b/tests/cases/conformance/externalModules/typeOnly/renamed.ts
new file mode 100644
index 0000000000000..266407b69e613
--- /dev/null
+++ b/tests/cases/conformance/externalModules/typeOnly/renamed.ts
@@ -0,0 +1,11 @@
+// @strict: true
+// @Filename: /a.ts
+class A { a!: string }
+export type { A as B };
+
+// @Filename: /b.ts
+export type { B as C } from './a';
+
+// @Filename: /c.ts
+import type { C as D } from './b';
+const d: D = {};
diff --git a/tests/cases/fourslash/codeFixConvertToTypeOnlyExport1.ts b/tests/cases/fourslash/codeFixConvertToTypeOnlyExport1.ts
new file mode 100644
index 0000000000000..00c9083f37720
--- /dev/null
+++ b/tests/cases/fourslash/codeFixConvertToTypeOnlyExport1.ts
@@ -0,0 +1,18 @@
+/// <reference path="fourslash.ts" />
+
+// @isolatedModules: true
+
+// @Filename: /a.ts
+////export type A = {};
+////export type B = {};
+
+// @Filename: /b.ts
+////export { A, B } from './a';
+
+goTo.file("/b.ts");
+verify.codeFix({
+  index: 0,
+  description: ts.Diagnostics.Convert_to_type_only_export.message,
+  errorCode: ts.Diagnostics.Re_exporting_a_type_when_the_isolatedModules_flag_is_provided_requires_using_export_type.code,
+  newFileContent: "export type { A, B } from './a';"
+});
diff --git a/tests/cases/fourslash/codeFixConvertToTypeOnlyExport2.ts b/tests/cases/fourslash/codeFixConvertToTypeOnlyExport2.ts
new file mode 100644
index 0000000000000..16733b082ab04
--- /dev/null
+++ b/tests/cases/fourslash/codeFixConvertToTypeOnlyExport2.ts
@@ -0,0 +1,22 @@
+/// <reference path="fourslash.ts" />
+
+// @isolatedModules: true
+
+// @Filename: /a.ts
+////export type A = {};
+////export const B = {};
+////export type C = {};
+
+// @Filename: /b.ts
+////export { A, B, C } from './a';
+
+goTo.file("/b.ts");
+verify.codeFix({
+  index: 0,
+  description: ts.Diagnostics.Convert_to_type_only_export.message,
+  errorCode: ts.Diagnostics.Re_exporting_a_type_when_the_isolatedModules_flag_is_provided_requires_using_export_type.code,
+  newFileContent:
+`export { B } from './a';
+export type { A, C } from './a';
+`
+});
diff --git a/tests/cases/fourslash/codeFixConvertToTypeOnlyExport3.ts b/tests/cases/fourslash/codeFixConvertToTypeOnlyExport3.ts
new file mode 100644
index 0000000000000..f90e0657d511d
--- /dev/null
+++ b/tests/cases/fourslash/codeFixConvertToTypeOnlyExport3.ts
@@ -0,0 +1,29 @@
+/// <reference path="fourslash.ts" />
+
+// @isolatedModules: true
+
+// @Filename: /a.ts
+////export type T1 = {};
+////export const V1 = {};
+////export type T2 = {};
+
+// @Filename: /b.ts
+////export type T3 = {};
+////export const V2 = {};
+////export type T4 = {};
+
+// @Filename: /c.ts
+////export { T1, V1, T2 } from './a';
+////export { T3, V2, T4 } from './b';
+
+goTo.file("/c.ts");
+verify.codeFixAll({
+  fixAllDescription: ts.Diagnostics.Convert_all_re_exported_types_to_type_only_exports.message,
+  fixId: "convertToTypeOnlyExport",
+  newFileContent:
+`export { V1 } from './a';
+export type { T1, T2 } from './a';
+export { V2 } from './b';
+export type { T3, T4 } from './b';
+`
+});
diff --git a/tests/cases/fourslash/codeFixInferFromUsageContextualImport2.ts b/tests/cases/fourslash/codeFixInferFromUsageContextualImport2.ts
index f12f9dc9e80ed..8b88015bcfd50 100644
--- a/tests/cases/fourslash/codeFixInferFromUsageContextualImport2.ts
+++ b/tests/cases/fourslash/codeFixInferFromUsageContextualImport2.ts
@@ -20,7 +20,7 @@ goTo.file("/b.ts");
 verify.codeFix({
   description: "Infer parameter types from usage",
   newFileContent:
-`import { User } from "./a";
+`import type { User } from "./a";
 
 export function f(user: User) {
     getEmail(user);
diff --git a/tests/cases/fourslash/codeFixSplitTypeOnlyImport.ts b/tests/cases/fourslash/codeFixSplitTypeOnlyImport.ts
new file mode 100644
index 0000000000000..00607ac2fc071
--- /dev/null
+++ b/tests/cases/fourslash/codeFixSplitTypeOnlyImport.ts
@@ -0,0 +1,39 @@
+/// <reference path="fourslash.ts" />
+
+// @Filename: /a.ts
+////export type B = {};
+////export type C = {};
+////export default interface A {}
+
+// @Filename: /b.ts
+////export type E = {};
+////export type F = {};
+////export default class D {}
+
+// @Filename: /c.ts
+////import type A, { B, C } from './a';
+////import type D, * as types from './b';
+
+goTo.file("/c.ts");
+
+verify.codeFix({
+  errorCode: ts.Diagnostics.A_type_only_import_can_specify_a_default_import_or_named_bindings_but_not_both.code,
+  description: ts.Diagnostics.Split_into_two_separate_import_declarations.message,
+  applyChanges: false,
+  index: 0,
+  newFileContent:
+`import type A from './a';
+import type { B, C } from './a';
+import type D, * as types from './b';`
+});
+
+verify.codeFixAll({
+  fixId: "splitTypeOnlyImport",
+  fixAllDescription: ts.Diagnostics.Split_all_invalid_type_only_imports.message,
+  newFileContent:
+`import type A from './a';
+import type { B, C } from './a';
+import type D from './b';
+import type * as types from './b';
+`
+});
diff --git a/tests/cases/fourslash/completionsImport_exportEquals.ts b/tests/cases/fourslash/completionsImport_exportEquals.ts
index 1ea3e7e637ea8..4a5d5fdd16d4d 100644
--- a/tests/cases/fourslash/completionsImport_exportEquals.ts
+++ b/tests/cases/fourslash/completionsImport_exportEquals.ts
@@ -17,7 +17,7 @@ const preferences: FourSlashInterface.UserPreferences = { includeCompletionsForM
 verify.completions(
     {
         marker: "0",
-        includes: {
+        includes: {
             name: "a",
             source: "/a",
             hasAction: true,
@@ -28,10 +28,10 @@ verify.completions(
     {
         marker: "1",
         includes: {
-            name: "b",
-            source: "/a",
-            hasAction: true,
-            sortText: completion.SortText.AutoImportSuggestions
+            name: "b",
+            source: "/a",
+            hasAction: true,
+            sortText: completion.SortText.AutoImportSuggestions
         },
         preferences,
     }
@@ -43,7 +43,7 @@ verify.applyCodeActionFromCompletion("1", {
     source: "/a",
     description: `Import 'b' from module "./a"`,
     newFileContent:
-`import { b } from "./a";
+`import type { b } from "./a";
 
 a;
 let x: b;`,
@@ -54,7 +54,7 @@ verify.applyCodeActionFromCompletion("0", {
     source: "/a",
     description: `Import 'a' from module "./a"`,
     newFileContent:
-`import { b } from "./a";
+`import type { b } from "./a";
 import a = require("./a");
 
 a;
diff --git a/tests/cases/fourslash/completionsTypeOnlyNamespace.ts b/tests/cases/fourslash/completionsTypeOnlyNamespace.ts
new file mode 100644
index 0000000000000..429353886f016
--- /dev/null
+++ b/tests/cases/fourslash/completionsTypeOnlyNamespace.ts
@@ -0,0 +1,23 @@
+/// <reference path="fourslash.ts" />
+
+// @Filename: /a.ts
+////export namespace ns {
+////  export class Box<T> {}
+////  export type Type = {};
+////  export const Value = {};
+////}
+
+// @Filename: /b.ts
+////import type { ns } from './a';
+////let x: ns./**/
+
+verify.completions({
+  marker: "",
+  exact: [{
+    name: "Box",
+    text: "class ns.Box<T>",
+  }, {
+    name: "Type",
+    text: "type ns.Type = {}"
+  }]
+});
diff --git a/tests/cases/fourslash/goToDefinitionTypeOnlyImport.ts b/tests/cases/fourslash/goToDefinitionTypeOnlyImport.ts
new file mode 100644
index 0000000000000..f7a9da33d9b67
--- /dev/null
+++ b/tests/cases/fourslash/goToDefinitionTypeOnlyImport.ts
@@ -0,0 +1,15 @@
+/// <reference path='fourslash.ts' />
+
+// @Filename: /a.ts
+////enum /*1*/SyntaxKind { SourceFile }
+////export type { SyntaxKind }
+
+// @Filename: /b.ts
+//// export type { SyntaxKind } from './a';
+
+// @Filename: /c.ts
+////import type { SyntaxKind } from './b';
+////let kind: [|/*2*/SyntaxKind|];
+
+
+verify.goToDefinition("2", "1");
diff --git a/tests/cases/fourslash/importNameCodeFixNewImportFile3.ts b/tests/cases/fourslash/importNameCodeFixNewImportFile3.ts
index af7901e03e61c..30467e7654965 100644
--- a/tests/cases/fourslash/importNameCodeFixNewImportFile3.ts
+++ b/tests/cases/fourslash/importNameCodeFixNewImportFile3.ts
@@ -9,7 +9,7 @@
 //// }
 
 verify.importFixAtPosition([
-`import { XXX } from "./module";
+`import type { XXX } from "./module";
 
 let t: XXX.I;`
 ]);
\ No newline at end of file
diff --git a/tests/cases/fourslash/importNameCodeFixNewImportFile4.ts b/tests/cases/fourslash/importNameCodeFixNewImportFile4.ts
index 62cf48c4977b9..4d59eb28e5216 100644
--- a/tests/cases/fourslash/importNameCodeFixNewImportFile4.ts
+++ b/tests/cases/fourslash/importNameCodeFixNewImportFile4.ts
@@ -10,7 +10,7 @@
 //// }
 
 verify.importFixAtPosition([
-`import { A } from "./module";
+`import type { A } from "./module";
 
 let t: A.B.I;`
 ]);
\ No newline at end of file
diff --git a/tests/cases/fourslash/importNameCodeFixNewImportTypeOnly.ts b/tests/cases/fourslash/importNameCodeFixNewImportTypeOnly.ts
new file mode 100644
index 0000000000000..3b2b61bf7a597
--- /dev/null
+++ b/tests/cases/fourslash/importNameCodeFixNewImportTypeOnly.ts
@@ -0,0 +1,14 @@
+/// <reference path="fourslash.ts" />
+
+// @target: esnext
+
+// @Filename: /a.ts
+////export interface Car {}
+
+// @Filename: /b.ts
+////function drive(car: /**/Car) {}
+
+goTo.file("/b.ts");
+verify.importFixAtPosition([`import type { Car } from "./a";
+
+function drive(car: Car) {}`]);
diff --git a/tests/cases/fourslash/importNameCodeFix_exportEquals.ts b/tests/cases/fourslash/importNameCodeFix_exportEquals.ts
index 4ab87df7e7618..5dd9b9f100e7c 100644
--- a/tests/cases/fourslash/importNameCodeFix_exportEquals.ts
+++ b/tests/cases/fourslash/importNameCodeFix_exportEquals.ts
@@ -16,9 +16,9 @@ verify.codeFixAll({
     fixId: "fixMissingImport",
     fixAllDescription: "Add all missing imports",
     newFileContent:
-`import { b } from "./a";
+`import a = require("./a");
 
-import a = require("./a");
+import type { b } from "./a";
 
 a;
 let x: b;`,
diff --git a/tests/cases/fourslash/quickInfoTypeOnlyEnum.ts b/tests/cases/fourslash/quickInfoTypeOnlyEnum.ts
new file mode 100644
index 0000000000000..a7ca81b01eb5c
--- /dev/null
+++ b/tests/cases/fourslash/quickInfoTypeOnlyEnum.ts
@@ -0,0 +1,18 @@
+/// <reference path="fourslash.ts" />
+
+// @Filename: /a.ts
+////export enum SyntaxKind {
+////  SourceFile
+////}
+
+// @Filename: /b.ts
+////import type { SyntaxKind } from './a';
+////let x: SyntaxKind/*1*/;
+////let y: SyntaxKind./*2*/SourceFile;
+
+verify.quickInfoAt("1", [
+  "(alias) enum SyntaxKind",
+  "import SyntaxKind"
+].join("\n"));
+
+verify.quickInfoAt("2", "(enum member) SyntaxKind.SourceFile = 0");
\ No newline at end of file
diff --git a/tests/cases/fourslash/quickInfoTypeOnlyNamespaceAndClass.ts b/tests/cases/fourslash/quickInfoTypeOnlyNamespaceAndClass.ts
new file mode 100644
index 0000000000000..900306fcc24d2
--- /dev/null
+++ b/tests/cases/fourslash/quickInfoTypeOnlyNamespaceAndClass.ts
@@ -0,0 +1,13 @@
+/// <reference path="fourslash.ts" />
+
+// @Filename: /a.ts
+////export namespace ns {
+////  export class Box<T> {}
+////}
+
+// @Filename: /b.ts
+////import type { ns } from './a';
+////let x: /*1*/ns./*2*/Box<string>;
+
+verify.quickInfoAt("1", "(alias) namespace ns\nimport ns");
+verify.quickInfoAt("2", "class ns.Box<T>");