From ddae38d449d74ec03f2dc764c93b88b277fdbd76 Mon Sep 17 00:00:00 2001
From: Andrew Branch <andrew@wheream.io>
Date: Thu, 12 Jan 2023 14:32:51 -0800
Subject: [PATCH 1/8] Support `export type * from "mod"`

---
 src/compiler/checker.ts                       | 78 +++++++++++++----
 src/compiler/diagnosticMessages.json          |  4 -
 src/compiler/types.ts                         |  4 +
 src/compiler/utilitiesPublic.ts               |  3 +
 .../reference/exportNamespace4.errors.txt     | 16 ++--
 tests/baselines/reference/exportNamespace4.js |  3 +-
 .../reference/exportNamespace5.errors.txt     | 34 ++++++++
 tests/baselines/reference/exportNamespace5.js | 87 +++++++++++++++++++
 .../reference/exportNamespace5.symbols        | 63 ++++++++++++++
 .../reference/exportNamespace5.types          | 63 ++++++++++++++
 .../reference/exportNamespace6.errors.txt     | 24 +++++
 tests/baselines/reference/exportNamespace6.js | 59 +++++++++++++
 .../reference/exportNamespace6.symbols        | 30 +++++++
 .../reference/exportNamespace6.types          | 30 +++++++
 .../reference/exportNamespace7.errors.txt     | 46 ++++++++++
 tests/baselines/reference/exportNamespace7.js | 75 ++++++++++++++++
 .../reference/exportNamespace7.symbols        | 61 +++++++++++++
 .../reference/exportNamespace7.types          | 61 +++++++++++++
 .../reference/exportNamespace8.errors.txt     | 27 ++++++
 tests/baselines/reference/exportNamespace8.js | 78 +++++++++++++++++
 .../reference/exportNamespace8.symbols        | 40 +++++++++
 .../reference/exportNamespace8.types          | 40 +++++++++
 .../reference/exportNamespace9.errors.txt     | 36 ++++++++
 tests/baselines/reference/exportNamespace9.js | 76 ++++++++++++++++
 .../reference/exportNamespace9.symbols        | 49 +++++++++++
 .../reference/exportNamespace9.types          | 49 +++++++++++
 .../typeOnly/exportNamespace5.ts              | 24 +++++
 .../typeOnly/exportNamespace6.ts              | 14 +++
 .../typeOnly/exportNamespace7.ts              | 23 +++++
 .../typeOnly/exportNamespace8.ts              | 17 ++++
 .../typeOnly/exportNamespace9.ts              | 27 ++++++
 31 files changed, 1207 insertions(+), 34 deletions(-)
 create mode 100644 tests/baselines/reference/exportNamespace5.errors.txt
 create mode 100644 tests/baselines/reference/exportNamespace5.js
 create mode 100644 tests/baselines/reference/exportNamespace5.symbols
 create mode 100644 tests/baselines/reference/exportNamespace5.types
 create mode 100644 tests/baselines/reference/exportNamespace6.errors.txt
 create mode 100644 tests/baselines/reference/exportNamespace6.js
 create mode 100644 tests/baselines/reference/exportNamespace6.symbols
 create mode 100644 tests/baselines/reference/exportNamespace6.types
 create mode 100644 tests/baselines/reference/exportNamespace7.errors.txt
 create mode 100644 tests/baselines/reference/exportNamespace7.js
 create mode 100644 tests/baselines/reference/exportNamespace7.symbols
 create mode 100644 tests/baselines/reference/exportNamespace7.types
 create mode 100644 tests/baselines/reference/exportNamespace8.errors.txt
 create mode 100644 tests/baselines/reference/exportNamespace8.js
 create mode 100644 tests/baselines/reference/exportNamespace8.symbols
 create mode 100644 tests/baselines/reference/exportNamespace8.types
 create mode 100644 tests/baselines/reference/exportNamespace9.errors.txt
 create mode 100644 tests/baselines/reference/exportNamespace9.js
 create mode 100644 tests/baselines/reference/exportNamespace9.symbols
 create mode 100644 tests/baselines/reference/exportNamespace9.types
 create mode 100644 tests/cases/conformance/externalModules/typeOnly/exportNamespace5.ts
 create mode 100644 tests/cases/conformance/externalModules/typeOnly/exportNamespace6.ts
 create mode 100644 tests/cases/conformance/externalModules/typeOnly/exportNamespace7.ts
 create mode 100644 tests/cases/conformance/externalModules/typeOnly/exportNamespace8.ts
 create mode 100644 tests/cases/conformance/externalModules/typeOnly/exportNamespace9.ts

diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts
index 234b9ef18c675..98310cf091163 100644
--- a/src/compiler/checker.ts
+++ b/src/compiler/checker.ts
@@ -3386,7 +3386,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
                 if (result && errorLocation && meaning & SymbolFlags.Value && result.flags & SymbolFlags.Alias && !(result.flags & SymbolFlags.Value) && !isValidTypeOnlyAliasUseSite(errorLocation)) {
                     const typeOnlyDeclaration = getTypeOnlyAliasDeclaration(result, SymbolFlags.Value);
                     if (typeOnlyDeclaration) {
-                        const message = typeOnlyDeclaration.kind === SyntaxKind.ExportSpecifier
+                        const message = typeOnlyDeclaration.kind === SyntaxKind.ExportSpecifier || typeOnlyDeclaration.kind === SyntaxKind.ExportDeclaration
                             ? Diagnostics._0_cannot_be_used_as_a_value_because_it_was_exported_using_export_type
                             : Diagnostics._0_cannot_be_used_as_a_value_because_it_was_imported_using_import_type;
                         const unescapedName = unescapeLeadingUnderscores(name);
@@ -3407,7 +3407,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
             diagnostic,
             createDiagnosticForNode(
                 typeOnlyDeclaration,
-                typeOnlyDeclaration.kind === SyntaxKind.ExportSpecifier ? Diagnostics._0_was_exported_here : Diagnostics._0_was_imported_here,
+                typeOnlyDeclaration.kind === SyntaxKind.ExportSpecifier || typeOnlyDeclaration.kind === SyntaxKind.ExportDeclaration
+                    ? Diagnostics._0_was_exported_here
+                    : Diagnostics._0_was_imported_here,
                 unescapedName));
     }
 
@@ -3804,7 +3806,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
     function checkAndReportErrorForResolvingImportAliasToTypeOnlySymbol(node: ImportEqualsDeclaration, resolved: Symbol | undefined) {
         if (markSymbolOfAliasDeclarationIfTypeOnly(node, /*immediateTarget*/ undefined, resolved, /*overwriteEmpty*/ false) && !node.isTypeOnly) {
             const typeOnlyDeclaration = getTypeOnlyAliasDeclaration(getSymbolOfDeclaration(node))!;
-            const isExport = typeOnlyDeclaration.kind === SyntaxKind.ExportSpecifier;
+            const isExport = typeOnlyDeclaration.kind === SyntaxKind.ExportSpecifier || typeOnlyDeclaration.kind === SyntaxKind.ExportDeclaration;
             const message = isExport
                 ? Diagnostics.An_import_alias_cannot_reference_a_declaration_that_was_exported_using_export_type
                 : Diagnostics.An_import_alias_cannot_reference_a_declaration_that_was_imported_using_import_type;
@@ -3812,7 +3814,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
                 ? Diagnostics._0_was_exported_here
                 : Diagnostics._0_was_imported_here;
 
-            const name = unescapeLeadingUnderscores(typeOnlyDeclaration.name.escapedText);
+            // TODO: how to get name for export *?
+            const name = typeOnlyDeclaration.kind === SyntaxKind.ExportDeclaration ? "*" : unescapeLeadingUnderscores(typeOnlyDeclaration.name.escapedText);
             addRelatedInfo(error(node.moduleReference, message), createDiagnosticForNode(typeOnlyDeclaration, relatedMessage, name));
         }
     }
@@ -4025,7 +4028,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
         if (symbol.flags & SymbolFlags.Module) {
             const exportSymbol = getExportsOfSymbol(symbol).get(name.escapedText);
             const resolved = resolveSymbol(exportSymbol, dontResolveAlias);
-            markSymbolOfAliasDeclarationIfTypeOnly(specifier, exportSymbol, resolved, /*overwriteEmpty*/ false);
+            const exportStarDeclaration = getSymbolLinks(symbol).typeOnlyExportStarMap?.get(name.escapedText);
+            markSymbolOfAliasDeclarationIfTypeOnly(specifier, exportSymbol, resolved, /*overwriteEmpty*/ false, exportStarDeclaration, name.escapedText);
             return resolved;
         }
     }
@@ -4386,6 +4390,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
         immediateTarget: Symbol | undefined,
         finalTarget: Symbol | undefined,
         overwriteEmpty: boolean,
+        exportStarDeclaration?: ExportDeclaration & { readonly isTypeOnly: true },
+        exportStarName?: __String,
     ): boolean {
         if (!aliasDeclaration || isPropertyAccessExpression(aliasDeclaration)) return false;
 
@@ -4397,6 +4403,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
             links.typeOnlyDeclaration = aliasDeclaration;
             return true;
         }
+        if (exportStarDeclaration) {
+            const links = getSymbolLinks(sourceSymbol);
+            links.typeOnlyDeclaration = exportStarDeclaration;
+            if (sourceSymbol.escapedName !== exportStarName) {
+                links.typeOnlyExportStarName = exportStarName;
+            }
+            return true;
+        }
 
         const links = getSymbolLinks(sourceSymbol);
         return markSymbolOfAliasDeclarationIfTypeOnlyWorker(links, immediateTarget, overwriteEmpty)
@@ -4422,7 +4436,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
             return links.typeOnlyDeclaration || undefined;
         }
         if (links.typeOnlyDeclaration) {
-            return getAllSymbolFlags(resolveAlias(links.typeOnlyDeclaration.symbol)) & include ? links.typeOnlyDeclaration : undefined;
+            const resolved = links.typeOnlyDeclaration.kind === SyntaxKind.ExportDeclaration
+                ? resolveSymbol(getExportsOfModule(links.typeOnlyDeclaration.symbol.parent!).get(links.typeOnlyExportStarName || symbol.escapedName))!
+                : resolveAlias(links.typeOnlyDeclaration.symbol);
+            return getAllSymbolFlags(resolved) & include ? links.typeOnlyDeclaration : undefined;
         }
         return undefined;
     }
@@ -5133,7 +5150,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
 
     function getExportsOfModule(moduleSymbol: Symbol): SymbolTable {
         const links = getSymbolLinks(moduleSymbol);
-        return links.resolvedExports || (links.resolvedExports = getExportsOfModuleWorker(moduleSymbol));
+        if (!links.resolvedExports) {
+            const { exports, typeOnlyExportStarMap } = getExportsOfModuleWorker(moduleSymbol);
+            links.resolvedExports = exports;
+            links.typeOnlyExportStarMap = typeOnlyExportStarMap;
+        }
+        return links.resolvedExports;
     }
 
     interface ExportCollisionTracker {
@@ -5173,21 +5195,38 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
         });
     }
 
-    function getExportsOfModuleWorker(moduleSymbol: Symbol): SymbolTable {
+    function getExportsOfModuleWorker(moduleSymbol: Symbol) {
         const visitedSymbols: Symbol[] = [];
+        let typeOnlyExportStarMap: UnderscoreEscapedMap<ExportDeclaration & { readonly isTypeOnly: true }> | undefined;
+        const nonTypeOnlyNames = new Set<__String>();
 
         // A module defined by an 'export=' consists of one export that needs to be resolved
         moduleSymbol = resolveExternalModuleSymbol(moduleSymbol);
+        const exports = visit(moduleSymbol) || emptySymbols;
 
-        return visit(moduleSymbol) || emptySymbols;
+        if (typeOnlyExportStarMap) {
+            nonTypeOnlyNames.forEach(name => typeOnlyExportStarMap!.delete(name));
+        }
+
+        return {
+            exports,
+            typeOnlyExportStarMap,
+        };
 
         // The ES6 spec permits export * declarations in a module to circularly reference the module itself. For example,
         // module 'a' can 'export * from "b"' and 'b' can 'export * from "a"' without error.
-        function visit(symbol: Symbol | undefined): SymbolTable | undefined {
+        function visit(symbol: Symbol | undefined, exportStar?: ExportDeclaration, isTypeOnly?: boolean): SymbolTable | undefined {
+            if (!isTypeOnly && symbol?.exports) {
+                // Add non-type-only names before checking if we've visited this module,
+                // because we might have visited it via an 'export type *', and visiting
+                // again with 'export *' will override the type-onlyness of its exports.
+                symbol.exports.forEach((_, name) => nonTypeOnlyNames.add(name));
+            }
             if (!(symbol && symbol.exports && pushIfUnique(visitedSymbols, symbol))) {
                 return;
             }
             const symbols = new Map(symbol.exports);
+
             // All export * declarations are collected in an __export symbol by the binder
             const exportStars = symbol.exports.get(InternalSymbolName.ExportStar);
             if (exportStars) {
@@ -5196,7 +5235,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
                 if (exportStars.declarations) {
                     for (const node of exportStars.declarations) {
                         const resolvedModule = resolveExternalModuleName(node, (node as ExportDeclaration).moduleSpecifier!);
-                        const exportedSymbols = visit(resolvedModule);
+                        const exportedSymbols = visit(resolvedModule, node as ExportDeclaration, isTypeOnly || (node as ExportDeclaration).isTypeOnly);
                         extendExportSymbols(
                             nestedSymbols,
                             exportedSymbols,
@@ -5221,6 +5260,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
                 });
                 extendExportSymbols(symbols, nestedSymbols);
             }
+            if (exportStar?.isTypeOnly) {
+                typeOnlyExportStarMap ??= new Map();
+                symbols.forEach((_, escapedName) => typeOnlyExportStarMap!.set(
+                    escapedName,
+                    exportStar as ExportDeclaration & { readonly isTypeOnly: true }));
+            }
             return symbols;
         }
     }
@@ -12131,7 +12176,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
         if (!links[resolutionKind]) {
             const isStatic = resolutionKind === MembersOrExportsResolutionKind.resolvedExports;
             const earlySymbols = !isStatic ? symbol.members :
-                symbol.flags & SymbolFlags.Module ? getExportsOfModuleWorker(symbol) :
+                symbol.flags & SymbolFlags.Module ? getExportsOfModuleWorker(symbol).exports :
                 symbol.exports;
 
             // In the event we recursively resolve the members/exports of the symbol, we
@@ -42983,13 +43028,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
     }
 
     function checkGrammarExportDeclaration(node: ExportDeclaration): boolean {
-        if (node.isTypeOnly) {
-            if (node.exportClause?.kind === SyntaxKind.NamedExports) {
-                return checkGrammarNamedImportsOrExports(node.exportClause);
-            }
-            else {
-                return grammarErrorOnNode(node, Diagnostics.Only_named_exports_may_use_export_type);
-            }
+        if (node.isTypeOnly && node.exportClause?.kind === SyntaxKind.NamedExports) {
+            return checkGrammarNamedImportsOrExports(node.exportClause);
         }
         return false;
     }
diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json
index a2d3387381009..d83e6564a94f2 100644
--- a/src/compiler/diagnosticMessages.json
+++ b/src/compiler/diagnosticMessages.json
@@ -1196,10 +1196,6 @@
         "category": "Error",
         "code": 1382
     },
-    "Only named exports may use 'export type'.": {
-        "category": "Error",
-        "code": 1383
-    },
     "Function type notation must be parenthesized when used in a union type.": {
         "category": "Error",
         "code": 1385
diff --git a/src/compiler/types.ts b/src/compiler/types.ts
index 325e3c109bdbe..1b70520fed00a 100644
--- a/src/compiler/types.ts
+++ b/src/compiler/types.ts
@@ -3817,6 +3817,7 @@ export type TypeOnlyCompatibleAliasDeclaration =
     | ImportEqualsDeclaration
     | NamespaceImport
     | ImportOrExportSpecifier
+    | ExportDeclaration
     ;
 
 export type TypeOnlyAliasDeclaration =
@@ -3825,6 +3826,7 @@ export type TypeOnlyAliasDeclaration =
     | NamespaceImport & { readonly parent: ImportClause & { readonly isTypeOnly: true } }
     | ImportSpecifier & ({ readonly isTypeOnly: true } | { readonly parent: NamedImports & { readonly parent: ImportClause & { readonly isTypeOnly: true } } })
     | ExportSpecifier & ({ readonly isTypeOnly: true } | { readonly parent: NamedExports & { readonly parent: ExportDeclaration & { readonly isTypeOnly: true } } })
+    | ExportDeclaration & { readonly isTypeOnly: true } // export * from "mod"
     ;
 
 /**
@@ -5802,6 +5804,8 @@ export interface SymbolLinks {
     deferralParent?: Type;                      // Source union/intersection of a deferred type
     cjsExportMerged?: Symbol;                   // Version of the symbol with all non export= exports merged with the export= target
     typeOnlyDeclaration?: TypeOnlyAliasDeclaration | false; // First resolved alias declaration that makes the symbol only usable in type constructs
+    typeOnlyExportStarMap?: UnderscoreEscapedMap<ExportDeclaration & { readonly isTypeOnly: true }>; // Set on a module symbol when some of its exports were resolved through a 'export type * from "mod"' declaration
+    typeOnlyExportStarName?: __String;          // Set to the name of the symbol re-exported by an 'export type *' declaration, when different from the symbol name
     isConstructorDeclaredProperty?: boolean;    // Property declared through 'this.x = ...' assignment in constructor
     tupleLabelDeclaration?: NamedTupleMember | ParameterDeclaration; // Declaration associated with the tuple's label
     accessibleChainCache?: Map<string, Symbol[] | undefined>;
diff --git a/src/compiler/utilitiesPublic.ts b/src/compiler/utilitiesPublic.ts
index 7bb784a3a57bd..c8444b805a81a 100644
--- a/src/compiler/utilitiesPublic.ts
+++ b/src/compiler/utilitiesPublic.ts
@@ -54,6 +54,7 @@ import {
     EnumDeclaration,
     every,
     ExportAssignment,
+    ExportDeclaration,
     ExportSpecifier,
     Expression,
     FileReference,
@@ -1458,6 +1459,8 @@ export function isTypeOnlyImportOrExportDeclaration(node: Node): node is TypeOnl
         case SyntaxKind.ImportClause:
         case SyntaxKind.ImportEqualsDeclaration:
             return (node as ImportClause | ImportEqualsDeclaration).isTypeOnly;
+        case SyntaxKind.ExportDeclaration:
+            return (node as ExportDeclaration).isTypeOnly && !!(node as ExportDeclaration).moduleSpecifier && !(node as ExportDeclaration).exportClause;
         default:
             return false;
     }
diff --git a/tests/baselines/reference/exportNamespace4.errors.txt b/tests/baselines/reference/exportNamespace4.errors.txt
index 30b849456e67f..198589903ffed 100644
--- a/tests/baselines/reference/exportNamespace4.errors.txt
+++ b/tests/baselines/reference/exportNamespace4.errors.txt
@@ -1,23 +1,21 @@
-tests/cases/conformance/externalModules/typeOnly/b.ts(1,1): error TS1383: Only named exports may use 'export type'.
-tests/cases/conformance/externalModules/typeOnly/c.ts(1,1): error TS1383: Only named exports may use 'export type'.
+tests/cases/conformance/externalModules/typeOnly/d.ts(2,1): error TS1362: 'A' cannot be used as a value because it was exported using 'export type'.
 
 
 ==== tests/cases/conformance/externalModules/typeOnly/a.ts (0 errors) ====
     export class A {}
     
-==== tests/cases/conformance/externalModules/typeOnly/b.ts (1 errors) ====
+==== tests/cases/conformance/externalModules/typeOnly/b.ts (0 errors) ====
     export type * from './a'; // Grammar error
-    ~~~~~~~~~~~~~~~~~~~~~~~~~
-!!! error TS1383: Only named exports may use 'export type'.
     
-==== tests/cases/conformance/externalModules/typeOnly/c.ts (1 errors) ====
+==== tests/cases/conformance/externalModules/typeOnly/c.ts (0 errors) ====
     export type * as ns from './a'; // Grammar error
-    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-!!! error TS1383: Only named exports may use 'export type'.
     
-==== tests/cases/conformance/externalModules/typeOnly/d.ts (0 errors) ====
+==== tests/cases/conformance/externalModules/typeOnly/d.ts (1 errors) ====
     import { A } from './b';
     A;
+    ~
+!!! error TS1362: 'A' cannot be used as a value because it was exported using 'export type'.
+!!! related TS1377 tests/cases/conformance/externalModules/typeOnly/b.ts:1:1: 'A' was exported here.
     
 ==== tests/cases/conformance/externalModules/typeOnly/e.ts (0 errors) ====
     import { ns } from './c';
diff --git a/tests/baselines/reference/exportNamespace4.js b/tests/baselines/reference/exportNamespace4.js
index afab2c5f82b39..31e2d8442d07a 100644
--- a/tests/baselines/reference/exportNamespace4.js
+++ b/tests/baselines/reference/exportNamespace4.js
@@ -37,8 +37,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
 //// [d.js]
 "use strict";
 Object.defineProperty(exports, "__esModule", { value: true });
-var b_1 = require("./b");
-b_1.A;
+A;
 //// [e.js]
 "use strict";
 Object.defineProperty(exports, "__esModule", { value: true });
diff --git a/tests/baselines/reference/exportNamespace5.errors.txt b/tests/baselines/reference/exportNamespace5.errors.txt
new file mode 100644
index 0000000000000..d94580faeeba7
--- /dev/null
+++ b/tests/baselines/reference/exportNamespace5.errors.txt
@@ -0,0 +1,34 @@
+/c.ts(2,16): error TS1362: 'A' cannot be used as a value because it was exported using 'export type'.
+/c.ts(3,17): error TS1362: 'C' cannot be used as a value because it was exported using 'export type'.
+
+
+==== /a.ts (0 errors) ====
+    export class A {}
+    export class B {}
+    export class X {}
+    
+==== /b.ts (0 errors) ====
+    export type * from "./a";
+    export { X } from "./a";
+    
+==== /c.ts (2 errors) ====
+    import { A, B as C, X } from "./b";
+    let _: A = new A();   // Error
+                   ~
+!!! error TS1362: 'A' cannot be used as a value because it was exported using 'export type'.
+!!! related TS1377 /b.ts:1:1: 'A' was exported here.
+    let __: C = new C();  // Error
+                    ~
+!!! error TS1362: 'C' cannot be used as a value because it was exported using 'export type'.
+!!! related TS1377 /b.ts:1:1: 'C' was exported here.
+    let ___: X = new X(); // Ok
+    
+==== /d.ts (0 errors) ====
+    export type * from "./a";
+    export * from "./a";
+    
+==== /e.ts (0 errors) ====
+    import { A, B, X } from "./d";
+    let _: A = new A();   // Ok
+    let __: B = new B();  // Ok
+    let ___: X = new X(); // Ok
\ No newline at end of file
diff --git a/tests/baselines/reference/exportNamespace5.js b/tests/baselines/reference/exportNamespace5.js
new file mode 100644
index 0000000000000..ae61f9da7236d
--- /dev/null
+++ b/tests/baselines/reference/exportNamespace5.js
@@ -0,0 +1,87 @@
+//// [tests/cases/conformance/externalModules/typeOnly/exportNamespace5.ts] ////
+
+//// [a.ts]
+export class A {}
+export class B {}
+export class X {}
+
+//// [b.ts]
+export type * from "./a";
+export { X } from "./a";
+
+//// [c.ts]
+import { A, B as C, X } from "./b";
+let _: A = new A();   // Error
+let __: C = new C();  // Error
+let ___: X = new X(); // Ok
+
+//// [d.ts]
+export type * from "./a";
+export * from "./a";
+
+//// [e.ts]
+import { A, B, X } from "./d";
+let _: A = new A();   // Ok
+let __: B = new B();  // Ok
+let ___: X = new X(); // Ok
+
+//// [a.js]
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.X = exports.B = exports.A = void 0;
+var A = /** @class */ (function () {
+    function A() {
+    }
+    return A;
+}());
+exports.A = A;
+var B = /** @class */ (function () {
+    function B() {
+    }
+    return B;
+}());
+exports.B = B;
+var X = /** @class */ (function () {
+    function X() {
+    }
+    return X;
+}());
+exports.X = X;
+//// [b.js]
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.X = void 0;
+var a_1 = require("./a");
+Object.defineProperty(exports, "X", { enumerable: true, get: function () { return a_1.X; } });
+//// [c.js]
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+var b_1 = require("./b");
+var _ = new A(); // Error
+var __ = new C(); // Error
+var ___ = new b_1.X(); // Ok
+//// [d.js]
+"use strict";
+var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
+    if (k2 === undefined) k2 = k;
+    var desc = Object.getOwnPropertyDescriptor(m, k);
+    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
+      desc = { enumerable: true, get: function() { return m[k]; } };
+    }
+    Object.defineProperty(o, k2, desc);
+}) : (function(o, m, k, k2) {
+    if (k2 === undefined) k2 = k;
+    o[k2] = m[k];
+}));
+var __exportStar = (this && this.__exportStar) || function(m, exports) {
+    for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
+};
+Object.defineProperty(exports, "__esModule", { value: true });
+__exportStar(require("./a"), exports);
+//// [e.js]
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+var d_1 = require("./d");
+var _ = new d_1.A(); // Ok
+var __ = new d_1.B(); // Ok
+var ___ = new d_1.X(); // Ok
diff --git a/tests/baselines/reference/exportNamespace5.symbols b/tests/baselines/reference/exportNamespace5.symbols
new file mode 100644
index 0000000000000..da935da205c55
--- /dev/null
+++ b/tests/baselines/reference/exportNamespace5.symbols
@@ -0,0 +1,63 @@
+=== /a.ts ===
+export class A {}
+>A : Symbol(A, Decl(a.ts, 0, 0))
+
+export class B {}
+>B : Symbol(B, Decl(a.ts, 0, 17))
+
+export class X {}
+>X : Symbol(X, Decl(a.ts, 1, 17))
+
+=== /b.ts ===
+export type * from "./a";
+export { X } from "./a";
+>X : Symbol(X, Decl(b.ts, 1, 8))
+
+=== /c.ts ===
+import { A, B as C, X } from "./b";
+>A : Symbol(A, Decl(c.ts, 0, 8))
+>B : Symbol(C, Decl(a.ts, 0, 17))
+>C : Symbol(C, Decl(c.ts, 0, 11))
+>X : Symbol(X, Decl(c.ts, 0, 19))
+
+let _: A = new A();   // Error
+>_ : Symbol(_, Decl(c.ts, 1, 3))
+>A : Symbol(A, Decl(c.ts, 0, 8))
+>A : Symbol(A, Decl(c.ts, 0, 8))
+
+let __: C = new C();  // Error
+>__ : Symbol(__, Decl(c.ts, 2, 3))
+>C : Symbol(C, Decl(c.ts, 0, 11))
+>C : Symbol(C, Decl(c.ts, 0, 11))
+
+let ___: X = new X(); // Ok
+>___ : Symbol(___, Decl(c.ts, 3, 3))
+>X : Symbol(X, Decl(c.ts, 0, 19))
+>X : Symbol(X, Decl(c.ts, 0, 19))
+
+=== /d.ts ===
+
+export type * from "./a";
+export * from "./a";
+
+=== /e.ts ===
+import { A, B, X } from "./d";
+>A : Symbol(A, Decl(e.ts, 0, 8))
+>B : Symbol(B, Decl(e.ts, 0, 11))
+>X : Symbol(X, Decl(e.ts, 0, 14))
+
+let _: A = new A();   // Ok
+>_ : Symbol(_, Decl(e.ts, 1, 3))
+>A : Symbol(A, Decl(e.ts, 0, 8))
+>A : Symbol(A, Decl(e.ts, 0, 8))
+
+let __: B = new B();  // Ok
+>__ : Symbol(__, Decl(e.ts, 2, 3))
+>B : Symbol(B, Decl(e.ts, 0, 11))
+>B : Symbol(B, Decl(e.ts, 0, 11))
+
+let ___: X = new X(); // Ok
+>___ : Symbol(___, Decl(e.ts, 3, 3))
+>X : Symbol(X, Decl(e.ts, 0, 14))
+>X : Symbol(X, Decl(e.ts, 0, 14))
+
diff --git a/tests/baselines/reference/exportNamespace5.types b/tests/baselines/reference/exportNamespace5.types
new file mode 100644
index 0000000000000..59fdeb762b0e2
--- /dev/null
+++ b/tests/baselines/reference/exportNamespace5.types
@@ -0,0 +1,63 @@
+=== /a.ts ===
+export class A {}
+>A : A
+
+export class B {}
+>B : B
+
+export class X {}
+>X : X
+
+=== /b.ts ===
+export type * from "./a";
+export { X } from "./a";
+>X : typeof import("/a").X
+
+=== /c.ts ===
+import { A, B as C, X } from "./b";
+>A : typeof A
+>B : typeof C
+>C : typeof C
+>X : typeof X
+
+let _: A = new A();   // Error
+>_ : A
+>new A() : A
+>A : typeof A
+
+let __: C = new C();  // Error
+>__ : C
+>new C() : C
+>C : typeof C
+
+let ___: X = new X(); // Ok
+>___ : X
+>new X() : X
+>X : typeof X
+
+=== /d.ts ===
+
+export type * from "./a";
+export * from "./a";
+
+=== /e.ts ===
+import { A, B, X } from "./d";
+>A : typeof A
+>B : typeof B
+>X : typeof X
+
+let _: A = new A();   // Ok
+>_ : A
+>new A() : A
+>A : typeof A
+
+let __: B = new B();  // Ok
+>__ : B
+>new B() : B
+>B : typeof B
+
+let ___: X = new X(); // Ok
+>___ : X
+>new X() : X
+>X : typeof X
+
diff --git a/tests/baselines/reference/exportNamespace6.errors.txt b/tests/baselines/reference/exportNamespace6.errors.txt
new file mode 100644
index 0000000000000..b639df1663561
--- /dev/null
+++ b/tests/baselines/reference/exportNamespace6.errors.txt
@@ -0,0 +1,24 @@
+/d.ts(2,16): error TS1362: 'A' cannot be used as a value because it was exported using 'export type'.
+/d.ts(3,17): error TS1362: 'B' cannot be used as a value because it was exported using 'export type'.
+
+
+==== /a.ts (0 errors) ====
+    export class A {}
+    export class B {}
+    
+==== /b.ts (0 errors) ====
+    export type * from "./a";
+    
+==== /c.ts (0 errors) ====
+    export * from "./b";
+    
+==== /d.ts (2 errors) ====
+    import { A, B } from "./c";
+    let _: A = new A();  // Error
+                   ~
+!!! error TS1362: 'A' cannot be used as a value because it was exported using 'export type'.
+!!! related TS1377 /b.ts:1:1: 'A' was exported here.
+    let __: B = new B(); // Error
+                    ~
+!!! error TS1362: 'B' cannot be used as a value because it was exported using 'export type'.
+!!! related TS1377 /b.ts:1:1: 'B' was exported here.
\ No newline at end of file
diff --git a/tests/baselines/reference/exportNamespace6.js b/tests/baselines/reference/exportNamespace6.js
new file mode 100644
index 0000000000000..bc9ca8bdb5da1
--- /dev/null
+++ b/tests/baselines/reference/exportNamespace6.js
@@ -0,0 +1,59 @@
+//// [tests/cases/conformance/externalModules/typeOnly/exportNamespace6.ts] ////
+
+//// [a.ts]
+export class A {}
+export class B {}
+
+//// [b.ts]
+export type * from "./a";
+
+//// [c.ts]
+export * from "./b";
+
+//// [d.ts]
+import { A, B } from "./c";
+let _: A = new A();  // Error
+let __: B = new B(); // Error
+
+//// [a.js]
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.B = exports.A = void 0;
+var A = /** @class */ (function () {
+    function A() {
+    }
+    return A;
+}());
+exports.A = A;
+var B = /** @class */ (function () {
+    function B() {
+    }
+    return B;
+}());
+exports.B = B;
+//// [b.js]
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+//// [c.js]
+"use strict";
+var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
+    if (k2 === undefined) k2 = k;
+    var desc = Object.getOwnPropertyDescriptor(m, k);
+    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
+      desc = { enumerable: true, get: function() { return m[k]; } };
+    }
+    Object.defineProperty(o, k2, desc);
+}) : (function(o, m, k, k2) {
+    if (k2 === undefined) k2 = k;
+    o[k2] = m[k];
+}));
+var __exportStar = (this && this.__exportStar) || function(m, exports) {
+    for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
+};
+Object.defineProperty(exports, "__esModule", { value: true });
+__exportStar(require("./b"), exports);
+//// [d.js]
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+var _ = new A(); // Error
+var __ = new B(); // Error
diff --git a/tests/baselines/reference/exportNamespace6.symbols b/tests/baselines/reference/exportNamespace6.symbols
new file mode 100644
index 0000000000000..97f4e9cd4e09e
--- /dev/null
+++ b/tests/baselines/reference/exportNamespace6.symbols
@@ -0,0 +1,30 @@
+=== /a.ts ===
+export class A {}
+>A : Symbol(A, Decl(a.ts, 0, 0))
+
+export class B {}
+>B : Symbol(B, Decl(a.ts, 0, 17))
+
+=== /b.ts ===
+
+export type * from "./a";
+
+=== /c.ts ===
+
+export * from "./b";
+
+=== /d.ts ===
+import { A, B } from "./c";
+>A : Symbol(A, Decl(d.ts, 0, 8))
+>B : Symbol(B, Decl(d.ts, 0, 11))
+
+let _: A = new A();  // Error
+>_ : Symbol(_, Decl(d.ts, 1, 3))
+>A : Symbol(A, Decl(d.ts, 0, 8))
+>A : Symbol(A, Decl(d.ts, 0, 8))
+
+let __: B = new B(); // Error
+>__ : Symbol(__, Decl(d.ts, 2, 3))
+>B : Symbol(B, Decl(d.ts, 0, 11))
+>B : Symbol(B, Decl(d.ts, 0, 11))
+
diff --git a/tests/baselines/reference/exportNamespace6.types b/tests/baselines/reference/exportNamespace6.types
new file mode 100644
index 0000000000000..9b51612a2af64
--- /dev/null
+++ b/tests/baselines/reference/exportNamespace6.types
@@ -0,0 +1,30 @@
+=== /a.ts ===
+export class A {}
+>A : A
+
+export class B {}
+>B : B
+
+=== /b.ts ===
+
+export type * from "./a";
+
+=== /c.ts ===
+
+export * from "./b";
+
+=== /d.ts ===
+import { A, B } from "./c";
+>A : typeof A
+>B : typeof B
+
+let _: A = new A();  // Error
+>_ : A
+>new A() : A
+>A : typeof A
+
+let __: B = new B(); // Error
+>__ : B
+>new B() : B
+>B : typeof B
+
diff --git a/tests/baselines/reference/exportNamespace7.errors.txt b/tests/baselines/reference/exportNamespace7.errors.txt
new file mode 100644
index 0000000000000..c713c7ec4e12f
--- /dev/null
+++ b/tests/baselines/reference/exportNamespace7.errors.txt
@@ -0,0 +1,46 @@
+/c.ts(2,16): error TS1362: 'A' cannot be used as a value because it was exported using 'export type'.
+/c.ts(3,17): error TS1362: 'B' cannot be used as a value because it was exported using 'export type'.
+/e.ts(2,16): error TS1362: 'A' cannot be used as a value because it was exported using 'export type'.
+/e.ts(3,17): error TS1362: 'B' cannot be used as a value because it was exported using 'export type'.
+/e.ts(4,18): error TS1362: 'C' cannot be used as a value because it was exported using 'export type'.
+
+
+==== /a.ts (0 errors) ====
+    export class A {}
+    export class B {}
+    export class C {}
+    
+==== /b.ts (0 errors) ====
+    export type * from "./a";
+    export class C {}
+    
+==== /c.ts (2 errors) ====
+    import { A, B, C } from "./b";
+    let _: A = new A();  // Error
+                   ~
+!!! error TS1362: 'A' cannot be used as a value because it was exported using 'export type'.
+!!! related TS1377 /b.ts:1:1: 'A' was exported here.
+    let __: B = new B(); // Error
+                    ~
+!!! error TS1362: 'B' cannot be used as a value because it was exported using 'export type'.
+!!! related TS1377 /b.ts:1:1: 'B' was exported here.
+    let ___: C = new C(); // Ok
+    
+==== /d.ts (0 errors) ====
+    export type * from "./b";
+    
+==== /e.ts (3 errors) ====
+    import { A, B, C } from "./d";
+    let _: A = new A();   // Error
+                   ~
+!!! error TS1362: 'A' cannot be used as a value because it was exported using 'export type'.
+!!! related TS1377 /d.ts:1:1: 'A' was exported here.
+    let __: B = new B();  // Error
+                    ~
+!!! error TS1362: 'B' cannot be used as a value because it was exported using 'export type'.
+!!! related TS1377 /d.ts:1:1: 'B' was exported here.
+    let ___: C = new C(); // Error
+                     ~
+!!! error TS1362: 'C' cannot be used as a value because it was exported using 'export type'.
+!!! related TS1377 /d.ts:1:1: 'C' was exported here.
+    
\ No newline at end of file
diff --git a/tests/baselines/reference/exportNamespace7.js b/tests/baselines/reference/exportNamespace7.js
new file mode 100644
index 0000000000000..f1b1be12f1be1
--- /dev/null
+++ b/tests/baselines/reference/exportNamespace7.js
@@ -0,0 +1,75 @@
+//// [tests/cases/conformance/externalModules/typeOnly/exportNamespace7.ts] ////
+
+//// [a.ts]
+export class A {}
+export class B {}
+export class C {}
+
+//// [b.ts]
+export type * from "./a";
+export class C {}
+
+//// [c.ts]
+import { A, B, C } from "./b";
+let _: A = new A();  // Error
+let __: B = new B(); // Error
+let ___: C = new C(); // Ok
+
+//// [d.ts]
+export type * from "./b";
+
+//// [e.ts]
+import { A, B, C } from "./d";
+let _: A = new A();   // Error
+let __: B = new B();  // Error
+let ___: C = new C(); // Error
+
+
+//// [a.js]
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.C = exports.B = exports.A = void 0;
+var A = /** @class */ (function () {
+    function A() {
+    }
+    return A;
+}());
+exports.A = A;
+var B = /** @class */ (function () {
+    function B() {
+    }
+    return B;
+}());
+exports.B = B;
+var C = /** @class */ (function () {
+    function C() {
+    }
+    return C;
+}());
+exports.C = C;
+//// [b.js]
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.C = void 0;
+var C = /** @class */ (function () {
+    function C() {
+    }
+    return C;
+}());
+exports.C = C;
+//// [c.js]
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+var b_1 = require("./b");
+var _ = new A(); // Error
+var __ = new B(); // Error
+var ___ = new b_1.C(); // Ok
+//// [d.js]
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+//// [e.js]
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+var _ = new A(); // Error
+var __ = new B(); // Error
+var ___ = new C(); // Error
diff --git a/tests/baselines/reference/exportNamespace7.symbols b/tests/baselines/reference/exportNamespace7.symbols
new file mode 100644
index 0000000000000..3ed0c38720bbd
--- /dev/null
+++ b/tests/baselines/reference/exportNamespace7.symbols
@@ -0,0 +1,61 @@
+=== /a.ts ===
+export class A {}
+>A : Symbol(A, Decl(a.ts, 0, 0))
+
+export class B {}
+>B : Symbol(B, Decl(a.ts, 0, 17))
+
+export class C {}
+>C : Symbol(C, Decl(a.ts, 1, 17))
+
+=== /b.ts ===
+export type * from "./a";
+export class C {}
+>C : Symbol(C, Decl(b.ts, 0, 25))
+
+=== /c.ts ===
+import { A, B, C } from "./b";
+>A : Symbol(A, Decl(c.ts, 0, 8))
+>B : Symbol(B, Decl(c.ts, 0, 11))
+>C : Symbol(C, Decl(c.ts, 0, 14))
+
+let _: A = new A();  // Error
+>_ : Symbol(_, Decl(c.ts, 1, 3))
+>A : Symbol(A, Decl(c.ts, 0, 8))
+>A : Symbol(A, Decl(c.ts, 0, 8))
+
+let __: B = new B(); // Error
+>__ : Symbol(__, Decl(c.ts, 2, 3))
+>B : Symbol(B, Decl(c.ts, 0, 11))
+>B : Symbol(B, Decl(c.ts, 0, 11))
+
+let ___: C = new C(); // Ok
+>___ : Symbol(___, Decl(c.ts, 3, 3))
+>C : Symbol(C, Decl(c.ts, 0, 14))
+>C : Symbol(C, Decl(c.ts, 0, 14))
+
+=== /d.ts ===
+
+export type * from "./b";
+
+=== /e.ts ===
+import { A, B, C } from "./d";
+>A : Symbol(A, Decl(e.ts, 0, 8))
+>B : Symbol(B, Decl(e.ts, 0, 11))
+>C : Symbol(C, Decl(e.ts, 0, 14))
+
+let _: A = new A();   // Error
+>_ : Symbol(_, Decl(e.ts, 1, 3))
+>A : Symbol(A, Decl(e.ts, 0, 8))
+>A : Symbol(A, Decl(e.ts, 0, 8))
+
+let __: B = new B();  // Error
+>__ : Symbol(__, Decl(e.ts, 2, 3))
+>B : Symbol(B, Decl(e.ts, 0, 11))
+>B : Symbol(B, Decl(e.ts, 0, 11))
+
+let ___: C = new C(); // Error
+>___ : Symbol(___, Decl(e.ts, 3, 3))
+>C : Symbol(C, Decl(e.ts, 0, 14))
+>C : Symbol(C, Decl(e.ts, 0, 14))
+
diff --git a/tests/baselines/reference/exportNamespace7.types b/tests/baselines/reference/exportNamespace7.types
new file mode 100644
index 0000000000000..7ddebff0202cf
--- /dev/null
+++ b/tests/baselines/reference/exportNamespace7.types
@@ -0,0 +1,61 @@
+=== /a.ts ===
+export class A {}
+>A : A
+
+export class B {}
+>B : B
+
+export class C {}
+>C : C
+
+=== /b.ts ===
+export type * from "./a";
+export class C {}
+>C : C
+
+=== /c.ts ===
+import { A, B, C } from "./b";
+>A : typeof A
+>B : typeof B
+>C : typeof C
+
+let _: A = new A();  // Error
+>_ : A
+>new A() : A
+>A : typeof A
+
+let __: B = new B(); // Error
+>__ : B
+>new B() : B
+>B : typeof B
+
+let ___: C = new C(); // Ok
+>___ : C
+>new C() : C
+>C : typeof C
+
+=== /d.ts ===
+
+export type * from "./b";
+
+=== /e.ts ===
+import { A, B, C } from "./d";
+>A : typeof A
+>B : typeof B
+>C : typeof C
+
+let _: A = new A();   // Error
+>_ : A
+>new A() : A
+>A : typeof A
+
+let __: B = new B();  // Error
+>__ : B
+>new B() : B
+>B : typeof B
+
+let ___: C = new C(); // Error
+>___ : C
+>new C() : C
+>C : typeof C
+
diff --git a/tests/baselines/reference/exportNamespace8.errors.txt b/tests/baselines/reference/exportNamespace8.errors.txt
new file mode 100644
index 0000000000000..8ee301e187189
--- /dev/null
+++ b/tests/baselines/reference/exportNamespace8.errors.txt
@@ -0,0 +1,27 @@
+/c.ts(2,1): error TS2308: Module "./a" has already exported a member named 'B'. Consider explicitly re-exporting to resolve the ambiguity.
+/d.ts(2,16): error TS1362: 'A' cannot be used as a value because it was exported using 'export type'.
+
+
+==== /a.ts (0 errors) ====
+    export class A {}
+    export class B {}
+    
+==== /b.ts (0 errors) ====
+    export class B {}
+    export class C {}
+    
+==== /c.ts (1 errors) ====
+    export type * from "./a";
+    export * from "./b"; // Collision error
+    ~~~~~~~~~~~~~~~~~~~~
+!!! error TS2308: Module "./a" has already exported a member named 'B'. Consider explicitly re-exporting to resolve the ambiguity.
+    
+==== /d.ts (1 errors) ====
+    import { A, B, C } from "./c";
+    let _: A = new A();   // Error
+                   ~
+!!! error TS1362: 'A' cannot be used as a value because it was exported using 'export type'.
+!!! related TS1377 /c.ts:1:1: 'A' was exported here.
+    let __: B = new B();  // Ok
+    let ___: C = new C(); // Ok
+    
\ No newline at end of file
diff --git a/tests/baselines/reference/exportNamespace8.js b/tests/baselines/reference/exportNamespace8.js
new file mode 100644
index 0000000000000..43747e6d03eed
--- /dev/null
+++ b/tests/baselines/reference/exportNamespace8.js
@@ -0,0 +1,78 @@
+//// [tests/cases/conformance/externalModules/typeOnly/exportNamespace8.ts] ////
+
+//// [a.ts]
+export class A {}
+export class B {}
+
+//// [b.ts]
+export class B {}
+export class C {}
+
+//// [c.ts]
+export type * from "./a";
+export * from "./b"; // Collision error
+
+//// [d.ts]
+import { A, B, C } from "./c";
+let _: A = new A();   // Error
+let __: B = new B();  // Ok
+let ___: C = new C(); // Ok
+
+
+//// [a.js]
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.B = exports.A = void 0;
+var A = /** @class */ (function () {
+    function A() {
+    }
+    return A;
+}());
+exports.A = A;
+var B = /** @class */ (function () {
+    function B() {
+    }
+    return B;
+}());
+exports.B = B;
+//// [b.js]
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.C = exports.B = void 0;
+var B = /** @class */ (function () {
+    function B() {
+    }
+    return B;
+}());
+exports.B = B;
+var C = /** @class */ (function () {
+    function C() {
+    }
+    return C;
+}());
+exports.C = C;
+//// [c.js]
+"use strict";
+var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
+    if (k2 === undefined) k2 = k;
+    var desc = Object.getOwnPropertyDescriptor(m, k);
+    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
+      desc = { enumerable: true, get: function() { return m[k]; } };
+    }
+    Object.defineProperty(o, k2, desc);
+}) : (function(o, m, k, k2) {
+    if (k2 === undefined) k2 = k;
+    o[k2] = m[k];
+}));
+var __exportStar = (this && this.__exportStar) || function(m, exports) {
+    for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
+};
+Object.defineProperty(exports, "__esModule", { value: true });
+__exportStar(require("./b"), exports); // Collision error
+//// [d.js]
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+var c_1 = require("./c");
+var _ = new A(); // Error
+var __ = new c_1.B(); // Ok
+var ___ = new c_1.C(); // Ok
diff --git a/tests/baselines/reference/exportNamespace8.symbols b/tests/baselines/reference/exportNamespace8.symbols
new file mode 100644
index 0000000000000..934ea38573b11
--- /dev/null
+++ b/tests/baselines/reference/exportNamespace8.symbols
@@ -0,0 +1,40 @@
+=== /a.ts ===
+export class A {}
+>A : Symbol(A, Decl(a.ts, 0, 0))
+
+export class B {}
+>B : Symbol(B, Decl(a.ts, 0, 17))
+
+=== /b.ts ===
+export class B {}
+>B : Symbol(B, Decl(b.ts, 0, 0))
+
+export class C {}
+>C : Symbol(C, Decl(b.ts, 0, 17))
+
+=== /c.ts ===
+
+export type * from "./a";
+export * from "./b"; // Collision error
+
+=== /d.ts ===
+import { A, B, C } from "./c";
+>A : Symbol(A, Decl(d.ts, 0, 8))
+>B : Symbol(B, Decl(d.ts, 0, 11))
+>C : Symbol(C, Decl(d.ts, 0, 14))
+
+let _: A = new A();   // Error
+>_ : Symbol(_, Decl(d.ts, 1, 3))
+>A : Symbol(A, Decl(d.ts, 0, 8))
+>A : Symbol(A, Decl(d.ts, 0, 8))
+
+let __: B = new B();  // Ok
+>__ : Symbol(__, Decl(d.ts, 2, 3))
+>B : Symbol(B, Decl(d.ts, 0, 11))
+>B : Symbol(B, Decl(d.ts, 0, 11))
+
+let ___: C = new C(); // Ok
+>___ : Symbol(___, Decl(d.ts, 3, 3))
+>C : Symbol(C, Decl(d.ts, 0, 14))
+>C : Symbol(C, Decl(d.ts, 0, 14))
+
diff --git a/tests/baselines/reference/exportNamespace8.types b/tests/baselines/reference/exportNamespace8.types
new file mode 100644
index 0000000000000..12b329db47542
--- /dev/null
+++ b/tests/baselines/reference/exportNamespace8.types
@@ -0,0 +1,40 @@
+=== /a.ts ===
+export class A {}
+>A : A
+
+export class B {}
+>B : B
+
+=== /b.ts ===
+export class B {}
+>B : B
+
+export class C {}
+>C : C
+
+=== /c.ts ===
+
+export type * from "./a";
+export * from "./b"; // Collision error
+
+=== /d.ts ===
+import { A, B, C } from "./c";
+>A : typeof A
+>B : typeof B
+>C : typeof C
+
+let _: A = new A();   // Error
+>_ : A
+>new A() : A
+>A : typeof A
+
+let __: B = new B();  // Ok
+>__ : B
+>new B() : B
+>B : typeof B
+
+let ___: C = new C(); // Ok
+>___ : C
+>new C() : C
+>C : typeof C
+
diff --git a/tests/baselines/reference/exportNamespace9.errors.txt b/tests/baselines/reference/exportNamespace9.errors.txt
new file mode 100644
index 0000000000000..a7df9f03bd748
--- /dev/null
+++ b/tests/baselines/reference/exportNamespace9.errors.txt
@@ -0,0 +1,36 @@
+/f.ts(2,1): error TS2308: Module "./e" has already exported a member named 'A'. Consider explicitly re-exporting to resolve the ambiguity.
+/g.ts(3,10): error TS2749: 'A' refers to a value, but is being used as a type here. Did you mean 'typeof A'?
+
+
+==== /a.ts (0 errors) ====
+    export type A = number;
+    
+==== /b.ts (0 errors) ====
+    export type * from "./a";
+    
+==== /c.ts (0 errors) ====
+    import { A } from "./b";
+    const A = 1;
+    export { A };
+    
+==== /d.ts (0 errors) ====
+    import { A } from "./c";
+    A; // Ok
+    type _ = A;
+    
+==== /e.ts (0 errors) ====
+    export const A = 1;
+    
+==== /f.ts (1 errors) ====
+    export * from "./e";
+    export type * from "./a"; // Collision error
+    ~~~~~~~~~~~~~~~~~~~~~~~~~
+!!! error TS2308: Module "./e" has already exported a member named 'A'. Consider explicitly re-exporting to resolve the ambiguity.
+    
+==== /g.ts (1 errors) ====
+    import { A } from "./f";
+    A;
+    type _ = A; // Follow-on from collision error
+             ~
+!!! error TS2749: 'A' refers to a value, but is being used as a type here. Did you mean 'typeof A'?
+    
\ No newline at end of file
diff --git a/tests/baselines/reference/exportNamespace9.js b/tests/baselines/reference/exportNamespace9.js
new file mode 100644
index 0000000000000..a0b5bb61edf5e
--- /dev/null
+++ b/tests/baselines/reference/exportNamespace9.js
@@ -0,0 +1,76 @@
+//// [tests/cases/conformance/externalModules/typeOnly/exportNamespace9.ts] ////
+
+//// [a.ts]
+export type A = number;
+
+//// [b.ts]
+export type * from "./a";
+
+//// [c.ts]
+import { A } from "./b";
+const A = 1;
+export { A };
+
+//// [d.ts]
+import { A } from "./c";
+A; // Ok
+type _ = A;
+
+//// [e.ts]
+export const A = 1;
+
+//// [f.ts]
+export * from "./e";
+export type * from "./a"; // Collision error
+
+//// [g.ts]
+import { A } from "./f";
+A;
+type _ = A; // Follow-on from collision error
+
+
+//// [a.js]
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+//// [b.js]
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+//// [c.js]
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.A = void 0;
+var A = 1;
+exports.A = A;
+//// [d.js]
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+var c_1 = require("./c");
+c_1.A; // Ok
+//// [e.js]
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.A = void 0;
+exports.A = 1;
+//// [f.js]
+"use strict";
+var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
+    if (k2 === undefined) k2 = k;
+    var desc = Object.getOwnPropertyDescriptor(m, k);
+    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
+      desc = { enumerable: true, get: function() { return m[k]; } };
+    }
+    Object.defineProperty(o, k2, desc);
+}) : (function(o, m, k, k2) {
+    if (k2 === undefined) k2 = k;
+    o[k2] = m[k];
+}));
+var __exportStar = (this && this.__exportStar) || function(m, exports) {
+    for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
+};
+Object.defineProperty(exports, "__esModule", { value: true });
+__exportStar(require("./e"), exports);
+//// [g.js]
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+var f_1 = require("./f");
+f_1.A;
diff --git a/tests/baselines/reference/exportNamespace9.symbols b/tests/baselines/reference/exportNamespace9.symbols
new file mode 100644
index 0000000000000..b0b81d8dce64d
--- /dev/null
+++ b/tests/baselines/reference/exportNamespace9.symbols
@@ -0,0 +1,49 @@
+=== /a.ts ===
+export type A = number;
+>A : Symbol(A, Decl(a.ts, 0, 0))
+
+=== /b.ts ===
+
+export type * from "./a";
+
+=== /c.ts ===
+import { A } from "./b";
+>A : Symbol(A, Decl(c.ts, 0, 8), Decl(c.ts, 1, 5))
+
+const A = 1;
+>A : Symbol(A, Decl(c.ts, 0, 8), Decl(c.ts, 1, 5))
+
+export { A };
+>A : Symbol(A, Decl(c.ts, 2, 8))
+
+=== /d.ts ===
+import { A } from "./c";
+>A : Symbol(A, Decl(d.ts, 0, 8))
+
+A; // Ok
+>A : Symbol(A, Decl(d.ts, 0, 8))
+
+type _ = A;
+>_ : Symbol(_, Decl(d.ts, 1, 2))
+>A : Symbol(A, Decl(d.ts, 0, 8))
+
+=== /e.ts ===
+export const A = 1;
+>A : Symbol(A, Decl(e.ts, 0, 12))
+
+=== /f.ts ===
+
+export * from "./e";
+export type * from "./a"; // Collision error
+
+=== /g.ts ===
+import { A } from "./f";
+>A : Symbol(A, Decl(g.ts, 0, 8))
+
+A;
+>A : Symbol(A, Decl(g.ts, 0, 8))
+
+type _ = A; // Follow-on from collision error
+>_ : Symbol(_, Decl(g.ts, 1, 2))
+>A : Symbol(A)
+
diff --git a/tests/baselines/reference/exportNamespace9.types b/tests/baselines/reference/exportNamespace9.types
new file mode 100644
index 0000000000000..d5f1fa1bf3685
--- /dev/null
+++ b/tests/baselines/reference/exportNamespace9.types
@@ -0,0 +1,49 @@
+=== /a.ts ===
+export type A = number;
+>A : number
+
+=== /b.ts ===
+
+export type * from "./a";
+
+=== /c.ts ===
+import { A } from "./b";
+>A : 1
+
+const A = 1;
+>A : 1
+>1 : 1
+
+export { A };
+>A : 1
+
+=== /d.ts ===
+import { A } from "./c";
+>A : 1
+
+A; // Ok
+>A : 1
+
+type _ = A;
+>_ : number
+
+=== /e.ts ===
+export const A = 1;
+>A : 1
+>1 : 1
+
+=== /f.ts ===
+
+export * from "./e";
+export type * from "./a"; // Collision error
+
+=== /g.ts ===
+import { A } from "./f";
+>A : 1
+
+A;
+>A : 1
+
+type _ = A; // Follow-on from collision error
+>_ : A
+
diff --git a/tests/cases/conformance/externalModules/typeOnly/exportNamespace5.ts b/tests/cases/conformance/externalModules/typeOnly/exportNamespace5.ts
new file mode 100644
index 0000000000000..c085d6ced438c
--- /dev/null
+++ b/tests/cases/conformance/externalModules/typeOnly/exportNamespace5.ts
@@ -0,0 +1,24 @@
+// @Filename: /a.ts
+export class A {}
+export class B {}
+export class X {}
+
+// @Filename: /b.ts
+export type * from "./a";
+export { X } from "./a";
+
+// @Filename: /c.ts
+import { A, B as C, X } from "./b";
+let _: A = new A();   // Error
+let __: C = new C();  // Error
+let ___: X = new X(); // Ok
+
+// @Filename: /d.ts
+export type * from "./a";
+export * from "./a";
+
+// @Filename: /e.ts
+import { A, B, X } from "./d";
+let _: A = new A();   // Ok
+let __: B = new B();  // Ok
+let ___: X = new X(); // Ok
\ No newline at end of file
diff --git a/tests/cases/conformance/externalModules/typeOnly/exportNamespace6.ts b/tests/cases/conformance/externalModules/typeOnly/exportNamespace6.ts
new file mode 100644
index 0000000000000..5574c8a7d1b68
--- /dev/null
+++ b/tests/cases/conformance/externalModules/typeOnly/exportNamespace6.ts
@@ -0,0 +1,14 @@
+// @Filename: /a.ts
+export class A {}
+export class B {}
+
+// @Filename: /b.ts
+export type * from "./a";
+
+// @Filename: /c.ts
+export * from "./b";
+
+// @Filename: /d.ts
+import { A, B } from "./c";
+let _: A = new A();  // Error
+let __: B = new B(); // Error
\ No newline at end of file
diff --git a/tests/cases/conformance/externalModules/typeOnly/exportNamespace7.ts b/tests/cases/conformance/externalModules/typeOnly/exportNamespace7.ts
new file mode 100644
index 0000000000000..7fa5688497761
--- /dev/null
+++ b/tests/cases/conformance/externalModules/typeOnly/exportNamespace7.ts
@@ -0,0 +1,23 @@
+// @Filename: /a.ts
+export class A {}
+export class B {}
+export class C {}
+
+// @Filename: /b.ts
+export type * from "./a";
+export class C {}
+
+// @Filename: /c.ts
+import { A, B, C } from "./b";
+let _: A = new A();  // Error
+let __: B = new B(); // Error
+let ___: C = new C(); // Ok
+
+// @Filename: /d.ts
+export type * from "./b";
+
+// @Filename: /e.ts
+import { A, B, C } from "./d";
+let _: A = new A();   // Error
+let __: B = new B();  // Error
+let ___: C = new C(); // Error
diff --git a/tests/cases/conformance/externalModules/typeOnly/exportNamespace8.ts b/tests/cases/conformance/externalModules/typeOnly/exportNamespace8.ts
new file mode 100644
index 0000000000000..2fab2f62f2bcc
--- /dev/null
+++ b/tests/cases/conformance/externalModules/typeOnly/exportNamespace8.ts
@@ -0,0 +1,17 @@
+// @Filename: /a.ts
+export class A {}
+export class B {}
+
+// @Filename: /b.ts
+export class B {}
+export class C {}
+
+// @Filename: /c.ts
+export type * from "./a";
+export * from "./b"; // Collision error
+
+// @Filename: /d.ts
+import { A, B, C } from "./c";
+let _: A = new A();   // Error
+let __: B = new B();  // Ok
+let ___: C = new C(); // Ok
diff --git a/tests/cases/conformance/externalModules/typeOnly/exportNamespace9.ts b/tests/cases/conformance/externalModules/typeOnly/exportNamespace9.ts
new file mode 100644
index 0000000000000..b3693b8b86721
--- /dev/null
+++ b/tests/cases/conformance/externalModules/typeOnly/exportNamespace9.ts
@@ -0,0 +1,27 @@
+// @Filename: /a.ts
+export type A = number;
+
+// @Filename: /b.ts
+export type * from "./a";
+
+// @Filename: /c.ts
+import { A } from "./b";
+const A = 1;
+export { A };
+
+// @Filename: /d.ts
+import { A } from "./c";
+A; // Ok
+type _ = A;
+
+// @Filename: /e.ts
+export const A = 1;
+
+// @Filename: /f.ts
+export * from "./e";
+export type * from "./a"; // Collision error
+
+// @Filename: /g.ts
+import { A } from "./f";
+A;
+type _ = A; // Follow-on from collision error

From 23e4a1448a3ff6f9f2a47db377f94bf0f91a8ffb Mon Sep 17 00:00:00 2001
From: Andrew Branch <andrew@wheream.io>
Date: Thu, 12 Jan 2023 14:43:34 -0800
Subject: [PATCH 2/8] Enable for namespace exports

---
 src/compiler/checker.ts                       |  4 +--
 src/compiler/types.ts                         |  2 ++
 src/compiler/utilitiesPublic.ts               |  3 ++
 .../reference/exportNamespace10.errors.txt    | 15 ++++++++++
 .../baselines/reference/exportNamespace10.js  | 29 +++++++++++++++++++
 .../reference/exportNamespace10.symbols       | 20 +++++++++++++
 .../reference/exportNamespace10.types         | 20 +++++++++++++
 .../typeOnly/exportNamespace10.ts             |  9 ++++++
 8 files changed, 100 insertions(+), 2 deletions(-)
 create mode 100644 tests/baselines/reference/exportNamespace10.errors.txt
 create mode 100644 tests/baselines/reference/exportNamespace10.js
 create mode 100644 tests/baselines/reference/exportNamespace10.symbols
 create mode 100644 tests/baselines/reference/exportNamespace10.types
 create mode 100644 tests/cases/conformance/externalModules/typeOnly/exportNamespace10.ts

diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts
index 98310cf091163..b47ae45f0351f 100644
--- a/src/compiler/checker.ts
+++ b/src/compiler/checker.ts
@@ -3386,7 +3386,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
                 if (result && errorLocation && meaning & SymbolFlags.Value && result.flags & SymbolFlags.Alias && !(result.flags & SymbolFlags.Value) && !isValidTypeOnlyAliasUseSite(errorLocation)) {
                     const typeOnlyDeclaration = getTypeOnlyAliasDeclaration(result, SymbolFlags.Value);
                     if (typeOnlyDeclaration) {
-                        const message = typeOnlyDeclaration.kind === SyntaxKind.ExportSpecifier || typeOnlyDeclaration.kind === SyntaxKind.ExportDeclaration
+                        const message = typeOnlyDeclaration.kind === SyntaxKind.ExportSpecifier || typeOnlyDeclaration.kind === SyntaxKind.ExportDeclaration || typeOnlyDeclaration.kind === SyntaxKind.NamespaceExport
                             ? Diagnostics._0_cannot_be_used_as_a_value_because_it_was_exported_using_export_type
                             : Diagnostics._0_cannot_be_used_as_a_value_because_it_was_imported_using_import_type;
                         const unescapedName = unescapeLeadingUnderscores(name);
@@ -3407,7 +3407,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
             diagnostic,
             createDiagnosticForNode(
                 typeOnlyDeclaration,
-                typeOnlyDeclaration.kind === SyntaxKind.ExportSpecifier || typeOnlyDeclaration.kind === SyntaxKind.ExportDeclaration
+                typeOnlyDeclaration.kind === SyntaxKind.ExportSpecifier || typeOnlyDeclaration.kind === SyntaxKind.ExportDeclaration || typeOnlyDeclaration.kind === SyntaxKind.NamespaceExport
                     ? Diagnostics._0_was_exported_here
                     : Diagnostics._0_was_imported_here,
                 unescapedName));
diff --git a/src/compiler/types.ts b/src/compiler/types.ts
index 1b70520fed00a..b23552c87055e 100644
--- a/src/compiler/types.ts
+++ b/src/compiler/types.ts
@@ -3818,6 +3818,7 @@ export type TypeOnlyCompatibleAliasDeclaration =
     | NamespaceImport
     | ImportOrExportSpecifier
     | ExportDeclaration
+    | NamespaceExport
     ;
 
 export type TypeOnlyAliasDeclaration =
@@ -3827,6 +3828,7 @@ export type TypeOnlyAliasDeclaration =
     | ImportSpecifier & ({ readonly isTypeOnly: true } | { readonly parent: NamedImports & { readonly parent: ImportClause & { readonly isTypeOnly: true } } })
     | ExportSpecifier & ({ readonly isTypeOnly: true } | { readonly parent: NamedExports & { readonly parent: ExportDeclaration & { readonly isTypeOnly: true } } })
     | ExportDeclaration & { readonly isTypeOnly: true } // export * from "mod"
+    | NamespaceExport & { readonly parent: ExportDeclaration & { readonly isTypeOnly: true } } // export * as ns from "mod"
     ;
 
 /**
diff --git a/src/compiler/utilitiesPublic.ts b/src/compiler/utilitiesPublic.ts
index c8444b805a81a..a9509dfa9d17f 100644
--- a/src/compiler/utilitiesPublic.ts
+++ b/src/compiler/utilitiesPublic.ts
@@ -209,6 +209,7 @@ import {
     NamedExportBindings,
     NamedImportBindings,
     NamespaceBody,
+    NamespaceExport,
     NamespaceImport,
     NewExpression,
     Node,
@@ -1461,6 +1462,8 @@ export function isTypeOnlyImportOrExportDeclaration(node: Node): node is TypeOnl
             return (node as ImportClause | ImportEqualsDeclaration).isTypeOnly;
         case SyntaxKind.ExportDeclaration:
             return (node as ExportDeclaration).isTypeOnly && !!(node as ExportDeclaration).moduleSpecifier && !(node as ExportDeclaration).exportClause;
+        case SyntaxKind.NamespaceExport:
+            return (node as NamespaceExport).parent.isTypeOnly;
         default:
             return false;
     }
diff --git a/tests/baselines/reference/exportNamespace10.errors.txt b/tests/baselines/reference/exportNamespace10.errors.txt
new file mode 100644
index 0000000000000..662fd40c92d4c
--- /dev/null
+++ b/tests/baselines/reference/exportNamespace10.errors.txt
@@ -0,0 +1,15 @@
+/c.ts(2,19): error TS1362: 'ns' cannot be used as a value because it was exported using 'export type'.
+
+
+==== /a.ts (0 errors) ====
+    export class A {}
+    
+==== /b.ts (0 errors) ====
+    export type * as ns from "./a";
+    
+==== /c.ts (1 errors) ====
+    import { ns } from "./b";
+    let _: ns.A = new ns.A(); // Error
+                      ~~
+!!! error TS1362: 'ns' cannot be used as a value because it was exported using 'export type'.
+!!! related TS1377 /b.ts:1:13: 'ns' was exported here.
\ No newline at end of file
diff --git a/tests/baselines/reference/exportNamespace10.js b/tests/baselines/reference/exportNamespace10.js
new file mode 100644
index 0000000000000..4ed852f618bde
--- /dev/null
+++ b/tests/baselines/reference/exportNamespace10.js
@@ -0,0 +1,29 @@
+//// [tests/cases/conformance/externalModules/typeOnly/exportNamespace10.ts] ////
+
+//// [a.ts]
+export class A {}
+
+//// [b.ts]
+export type * as ns from "./a";
+
+//// [c.ts]
+import { ns } from "./b";
+let _: ns.A = new ns.A(); // Error
+
+//// [a.js]
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.A = void 0;
+var A = /** @class */ (function () {
+    function A() {
+    }
+    return A;
+}());
+exports.A = A;
+//// [b.js]
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+//// [c.js]
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+var _ = new ns.A(); // Error
diff --git a/tests/baselines/reference/exportNamespace10.symbols b/tests/baselines/reference/exportNamespace10.symbols
new file mode 100644
index 0000000000000..367d0222a89c4
--- /dev/null
+++ b/tests/baselines/reference/exportNamespace10.symbols
@@ -0,0 +1,20 @@
+=== /a.ts ===
+export class A {}
+>A : Symbol(A, Decl(a.ts, 0, 0))
+
+=== /b.ts ===
+export type * as ns from "./a";
+>ns : Symbol(ns, Decl(b.ts, 0, 11))
+
+=== /c.ts ===
+import { ns } from "./b";
+>ns : Symbol(ns, Decl(c.ts, 0, 8))
+
+let _: ns.A = new ns.A(); // Error
+>_ : Symbol(_, Decl(c.ts, 1, 3))
+>ns : Symbol(ns, Decl(c.ts, 0, 8))
+>A : Symbol(ns.A, Decl(a.ts, 0, 0))
+>ns.A : Symbol(ns.A, Decl(a.ts, 0, 0))
+>ns : Symbol(ns, Decl(c.ts, 0, 8))
+>A : Symbol(ns.A, Decl(a.ts, 0, 0))
+
diff --git a/tests/baselines/reference/exportNamespace10.types b/tests/baselines/reference/exportNamespace10.types
new file mode 100644
index 0000000000000..a9976401137f5
--- /dev/null
+++ b/tests/baselines/reference/exportNamespace10.types
@@ -0,0 +1,20 @@
+=== /a.ts ===
+export class A {}
+>A : A
+
+=== /b.ts ===
+export type * as ns from "./a";
+>ns : typeof import("/a")
+
+=== /c.ts ===
+import { ns } from "./b";
+>ns : typeof ns
+
+let _: ns.A = new ns.A(); // Error
+>_ : ns.A
+>ns : any
+>new ns.A() : ns.A
+>ns.A : typeof ns.A
+>ns : typeof ns
+>A : typeof ns.A
+
diff --git a/tests/cases/conformance/externalModules/typeOnly/exportNamespace10.ts b/tests/cases/conformance/externalModules/typeOnly/exportNamespace10.ts
new file mode 100644
index 0000000000000..05a3baf824abc
--- /dev/null
+++ b/tests/cases/conformance/externalModules/typeOnly/exportNamespace10.ts
@@ -0,0 +1,9 @@
+// @Filename: /a.ts
+export class A {}
+
+// @Filename: /b.ts
+export type * as ns from "./a";
+
+// @Filename: /c.ts
+import { ns } from "./b";
+let _: ns.A = new ns.A(); // Error
\ No newline at end of file

From 08701ac6e987987e30984bb040b097216a0a07bf Mon Sep 17 00:00:00 2001
From: Andrew Branch <andrew@wheream.io>
Date: Thu, 12 Jan 2023 15:01:46 -0800
Subject: [PATCH 3/8] Clean up some types

---
 src/compiler/types.ts           |  7 ++++++-
 src/compiler/utilitiesPublic.ts | 23 +++++++++++++++++------
 src/services/completions.ts     | 13 +++++++------
 3 files changed, 30 insertions(+), 13 deletions(-)

diff --git a/src/compiler/types.ts b/src/compiler/types.ts
index b23552c87055e..04b41852ca6e9 100644
--- a/src/compiler/types.ts
+++ b/src/compiler/types.ts
@@ -3821,16 +3821,21 @@ export type TypeOnlyCompatibleAliasDeclaration =
     | NamespaceExport
     ;
 
-export type TypeOnlyAliasDeclaration =
+export type TypeOnlyImportDeclaration =
     | ImportClause & { readonly isTypeOnly: true, readonly name: Identifier }
     | ImportEqualsDeclaration & { readonly isTypeOnly: true }
     | NamespaceImport & { readonly parent: ImportClause & { readonly isTypeOnly: true } }
     | ImportSpecifier & ({ readonly isTypeOnly: true } | { readonly parent: NamedImports & { readonly parent: ImportClause & { readonly isTypeOnly: true } } })
+    ;
+
+export type TypeOnlyExportDeclaration =
     | ExportSpecifier & ({ readonly isTypeOnly: true } | { readonly parent: NamedExports & { readonly parent: ExportDeclaration & { readonly isTypeOnly: true } } })
     | ExportDeclaration & { readonly isTypeOnly: true } // export * from "mod"
     | NamespaceExport & { readonly parent: ExportDeclaration & { readonly isTypeOnly: true } } // export * as ns from "mod"
     ;
 
+export type TypeOnlyAliasDeclaration = TypeOnlyImportDeclaration | TypeOnlyExportDeclaration;
+
 /**
  * This is either an `export =` or an `export default` declaration.
  * Unless `isExportEquals` is set, this node was parsed as an `export default`.
diff --git a/src/compiler/utilitiesPublic.ts b/src/compiler/utilitiesPublic.ts
index a9509dfa9d17f..95703ddc11d2b 100644
--- a/src/compiler/utilitiesPublic.ts
+++ b/src/compiler/utilitiesPublic.ts
@@ -92,7 +92,6 @@ import {
     Identifier,
     ImportClause,
     ImportEqualsDeclaration,
-    ImportOrExportSpecifier,
     ImportSpecifier,
     ImportTypeNode,
     isAccessExpression,
@@ -263,6 +262,8 @@ import {
     TypeElement,
     TypeNode,
     TypeOnlyAliasDeclaration,
+    TypeOnlyExportDeclaration,
+    TypeOnlyImportDeclaration,
     TypeParameterDeclaration,
     TypeReferenceType,
     UnaryExpression,
@@ -1450,23 +1451,33 @@ export function isImportOrExportSpecifier(node: Node): node is ImportSpecifier |
     return isImportSpecifier(node) || isExportSpecifier(node);
 }
 
-export function isTypeOnlyImportOrExportDeclaration(node: Node): node is TypeOnlyAliasDeclaration {
+export function isTypeOnlyImportDeclaration(node: Node): node is TypeOnlyImportDeclaration {
     switch (node.kind) {
         case SyntaxKind.ImportSpecifier:
-        case SyntaxKind.ExportSpecifier:
-            return (node as ImportOrExportSpecifier).isTypeOnly || (node as ImportOrExportSpecifier).parent.parent.isTypeOnly;
+            return (node as ImportSpecifier).isTypeOnly || (node as ImportSpecifier).parent.parent.isTypeOnly;
         case SyntaxKind.NamespaceImport:
             return (node as NamespaceImport).parent.isTypeOnly;
         case SyntaxKind.ImportClause:
         case SyntaxKind.ImportEqualsDeclaration:
             return (node as ImportClause | ImportEqualsDeclaration).isTypeOnly;
+    }
+    return false;
+}
+
+export function isTypeOnlyExportDeclaration(node: Node): node is TypeOnlyExportDeclaration {
+    switch (node.kind) {
+        case SyntaxKind.ExportSpecifier:
+            return (node as ExportSpecifier).isTypeOnly || (node as ExportSpecifier).parent.parent.isTypeOnly;
         case SyntaxKind.ExportDeclaration:
             return (node as ExportDeclaration).isTypeOnly && !!(node as ExportDeclaration).moduleSpecifier && !(node as ExportDeclaration).exportClause;
         case SyntaxKind.NamespaceExport:
             return (node as NamespaceExport).parent.isTypeOnly;
-        default:
-            return false;
     }
+    return false;
+}
+
+export function isTypeOnlyImportOrExportDeclaration(node: Node): node is TypeOnlyAliasDeclaration {
+    return isTypeOnlyImportDeclaration(node) || isTypeOnlyExportDeclaration(node);
 }
 
 export function isAssertionKey(node: Node): node is AssertionKey {
diff --git a/src/services/completions.ts b/src/services/completions.ts
index a166845ba3e97..e1be64a49bd95 100644
--- a/src/services/completions.ts
+++ b/src/services/completions.ts
@@ -227,6 +227,7 @@ import {
     isTypeLiteralNode,
     isTypeNode,
     isTypeOfExpression,
+    isTypeOnlyImportDeclaration,
     isTypeOnlyImportOrExportDeclaration,
     isTypeReferenceType,
     isValidTypeOnlyAliasUseSite,
@@ -351,7 +352,7 @@ import {
     typeHasCallOrConstructSignatures,
     TypeLiteralNode,
     TypeNode,
-    TypeOnlyAliasDeclaration,
+    TypeOnlyImportDeclaration,
     TypeQueryNode,
     TypeReferenceNode,
     unescapeLeadingUnderscores,
@@ -466,8 +467,8 @@ interface SymbolOriginInfoResolvedExport extends SymbolOriginInfo {
     moduleSpecifier: string;
 }
 
-interface SymbolOriginInfoTypeOnlyAlias extends SymbolOriginInfo {
-    declaration: TypeOnlyAliasDeclaration;
+interface SymbolOriginInfoTypeOnlyImport extends SymbolOriginInfo {
+    declaration: TypeOnlyImportDeclaration;
 }
 
 interface SymbolOriginInfoObjectLiteralMethod extends SymbolOriginInfo {
@@ -508,7 +509,7 @@ function originIsNullableMember(origin: SymbolOriginInfo): boolean {
     return !!(origin.kind & SymbolOriginInfoKind.Nullable);
 }
 
-function originIsTypeOnlyAlias(origin: SymbolOriginInfo | undefined): origin is SymbolOriginInfoTypeOnlyAlias {
+function originIsTypeOnlyAlias(origin: SymbolOriginInfo | undefined): origin is SymbolOriginInfoTypeOnlyImport {
     return !!(origin && origin.kind & SymbolOriginInfoKind.TypeOnlyAlias);
 }
 
@@ -3330,9 +3331,9 @@ function getCompletionData(
                 symbolToSortTextMap[getSymbolId(symbol)] = SortText.GlobalsOrKeywords;
             }
             if (typeOnlyAliasNeedsPromotion && !(symbol.flags & SymbolFlags.Value)) {
-                const typeOnlyAliasDeclaration = symbol.declarations && find(symbol.declarations, isTypeOnlyImportOrExportDeclaration);
+                const typeOnlyAliasDeclaration = symbol.declarations && find(symbol.declarations, isTypeOnlyImportDeclaration);
                 if (typeOnlyAliasDeclaration) {
-                    const origin: SymbolOriginInfoTypeOnlyAlias = { kind: SymbolOriginInfoKind.TypeOnlyAlias, declaration: typeOnlyAliasDeclaration };
+                    const origin: SymbolOriginInfoTypeOnlyImport = { kind: SymbolOriginInfoKind.TypeOnlyAlias, declaration: typeOnlyAliasDeclaration };
                     symbolToOriginInfoMap[i] = origin;
                 }
             }

From ef6162dff4489404ab00e0b98a44337cbec79b29 Mon Sep 17 00:00:00 2001
From: Andrew Branch <andrew@wheream.io>
Date: Thu, 12 Jan 2023 15:39:15 -0800
Subject: [PATCH 4/8] Update API

---
 .../reference/api/tsserverlibrary.d.ts         | 18 ++++++++++++++----
 tests/baselines/reference/api/typescript.d.ts  | 18 ++++++++++++++----
 2 files changed, 28 insertions(+), 8 deletions(-)

diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts
index 0884b10602045..1f1c14103a37a 100644
--- a/tests/baselines/reference/api/tsserverlibrary.d.ts
+++ b/tests/baselines/reference/api/tsserverlibrary.d.ts
@@ -5713,8 +5713,8 @@ declare namespace ts {
         readonly name: Identifier;
     }
     type ImportOrExportSpecifier = ImportSpecifier | ExportSpecifier;
-    type TypeOnlyCompatibleAliasDeclaration = ImportClause | ImportEqualsDeclaration | NamespaceImport | ImportOrExportSpecifier;
-    type TypeOnlyAliasDeclaration = ImportClause & {
+    type TypeOnlyCompatibleAliasDeclaration = ImportClause | ImportEqualsDeclaration | NamespaceImport | ImportOrExportSpecifier | ExportDeclaration | NamespaceExport;
+    type TypeOnlyImportDeclaration = ImportClause & {
         readonly isTypeOnly: true;
         readonly name: Identifier;
     } | ImportEqualsDeclaration & {
@@ -5731,7 +5731,8 @@ declare namespace ts {
                 readonly isTypeOnly: true;
             };
         };
-    }) | ExportSpecifier & ({
+    });
+    type TypeOnlyExportDeclaration = ExportSpecifier & ({
         readonly isTypeOnly: true;
     } | {
         readonly parent: NamedExports & {
@@ -5739,7 +5740,14 @@ declare namespace ts {
                 readonly isTypeOnly: true;
             };
         };
-    });
+    }) | ExportDeclaration & {
+        readonly isTypeOnly: true;
+    } | NamespaceExport & {
+        readonly parent: ExportDeclaration & {
+            readonly isTypeOnly: true;
+        };
+    };
+    type TypeOnlyAliasDeclaration = TypeOnlyImportDeclaration | TypeOnlyExportDeclaration;
     /**
      * This is either an `export =` or an `export default` declaration.
      * Unless `isExportEquals` is set, this node was parsed as an `export default`.
@@ -8732,6 +8740,8 @@ 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 isTypeOnlyImportDeclaration(node: Node): node is TypeOnlyImportDeclaration;
+    function isTypeOnlyExportDeclaration(node: Node): node is TypeOnlyExportDeclaration;
     function isTypeOnlyImportOrExportDeclaration(node: Node): node is TypeOnlyAliasDeclaration;
     function isAssertionKey(node: Node): node is AssertionKey;
     function isStringTextContainingNode(node: Node): node is StringLiteral | TemplateLiteralToken;
diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts
index 107407bd58e53..073257f8d4431 100644
--- a/tests/baselines/reference/api/typescript.d.ts
+++ b/tests/baselines/reference/api/typescript.d.ts
@@ -1778,8 +1778,8 @@ declare namespace ts {
         readonly name: Identifier;
     }
     type ImportOrExportSpecifier = ImportSpecifier | ExportSpecifier;
-    type TypeOnlyCompatibleAliasDeclaration = ImportClause | ImportEqualsDeclaration | NamespaceImport | ImportOrExportSpecifier;
-    type TypeOnlyAliasDeclaration = ImportClause & {
+    type TypeOnlyCompatibleAliasDeclaration = ImportClause | ImportEqualsDeclaration | NamespaceImport | ImportOrExportSpecifier | ExportDeclaration | NamespaceExport;
+    type TypeOnlyImportDeclaration = ImportClause & {
         readonly isTypeOnly: true;
         readonly name: Identifier;
     } | ImportEqualsDeclaration & {
@@ -1796,7 +1796,8 @@ declare namespace ts {
                 readonly isTypeOnly: true;
             };
         };
-    }) | ExportSpecifier & ({
+    });
+    type TypeOnlyExportDeclaration = ExportSpecifier & ({
         readonly isTypeOnly: true;
     } | {
         readonly parent: NamedExports & {
@@ -1804,7 +1805,14 @@ declare namespace ts {
                 readonly isTypeOnly: true;
             };
         };
-    });
+    }) | ExportDeclaration & {
+        readonly isTypeOnly: true;
+    } | NamespaceExport & {
+        readonly parent: ExportDeclaration & {
+            readonly isTypeOnly: true;
+        };
+    };
+    type TypeOnlyAliasDeclaration = TypeOnlyImportDeclaration | TypeOnlyExportDeclaration;
     /**
      * This is either an `export =` or an `export default` declaration.
      * Unless `isExportEquals` is set, this node was parsed as an `export default`.
@@ -4797,6 +4805,8 @@ 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 isTypeOnlyImportDeclaration(node: Node): node is TypeOnlyImportDeclaration;
+    function isTypeOnlyExportDeclaration(node: Node): node is TypeOnlyExportDeclaration;
     function isTypeOnlyImportOrExportDeclaration(node: Node): node is TypeOnlyAliasDeclaration;
     function isAssertionKey(node: Node): node is AssertionKey;
     function isStringTextContainingNode(node: Node): node is StringLiteral | TemplateLiteralToken;

From 09f7087c000665463f2130151cbd80d982854130 Mon Sep 17 00:00:00 2001
From: Andrew Branch <andrew@wheream.io>
Date: Thu, 12 Jan 2023 15:40:07 -0800
Subject: [PATCH 5/8] Update old test

---
 tests/baselines/reference/exportNamespace4.errors.txt  | 10 +++++++---
 tests/baselines/reference/exportNamespace4.js          |  7 +++----
 tests/baselines/reference/exportNamespace4.symbols     |  4 ++--
 tests/baselines/reference/exportNamespace4.types       |  4 ++--
 .../externalModules/typeOnly/exportNamespace4.ts       |  4 ++--
 5 files changed, 16 insertions(+), 13 deletions(-)

diff --git a/tests/baselines/reference/exportNamespace4.errors.txt b/tests/baselines/reference/exportNamespace4.errors.txt
index 198589903ffed..353b26b773aa8 100644
--- a/tests/baselines/reference/exportNamespace4.errors.txt
+++ b/tests/baselines/reference/exportNamespace4.errors.txt
@@ -1,14 +1,15 @@
 tests/cases/conformance/externalModules/typeOnly/d.ts(2,1): error TS1362: 'A' cannot be used as a value because it was exported using 'export type'.
+tests/cases/conformance/externalModules/typeOnly/e.ts(2,1): error TS1362: 'ns' cannot be used as a value because it was exported using 'export type'.
 
 
 ==== tests/cases/conformance/externalModules/typeOnly/a.ts (0 errors) ====
     export class A {}
     
 ==== tests/cases/conformance/externalModules/typeOnly/b.ts (0 errors) ====
-    export type * from './a'; // Grammar error
+    export type * from './a';
     
 ==== tests/cases/conformance/externalModules/typeOnly/c.ts (0 errors) ====
-    export type * as ns from './a'; // Grammar error
+    export type * as ns from './a';
     
 ==== tests/cases/conformance/externalModules/typeOnly/d.ts (1 errors) ====
     import { A } from './b';
@@ -17,7 +18,10 @@ tests/cases/conformance/externalModules/typeOnly/d.ts(2,1): error TS1362: 'A' ca
 !!! error TS1362: 'A' cannot be used as a value because it was exported using 'export type'.
 !!! related TS1377 tests/cases/conformance/externalModules/typeOnly/b.ts:1:1: 'A' was exported here.
     
-==== tests/cases/conformance/externalModules/typeOnly/e.ts (0 errors) ====
+==== tests/cases/conformance/externalModules/typeOnly/e.ts (1 errors) ====
     import { ns } from './c';
     ns.A;
+    ~~
+!!! error TS1362: 'ns' cannot be used as a value because it was exported using 'export type'.
+!!! related TS1377 tests/cases/conformance/externalModules/typeOnly/c.ts:1:13: 'ns' was exported here.
     
\ No newline at end of file
diff --git a/tests/baselines/reference/exportNamespace4.js b/tests/baselines/reference/exportNamespace4.js
index 31e2d8442d07a..faa416399761b 100644
--- a/tests/baselines/reference/exportNamespace4.js
+++ b/tests/baselines/reference/exportNamespace4.js
@@ -4,10 +4,10 @@
 export class A {}
 
 //// [b.ts]
-export type * from './a'; // Grammar error
+export type * from './a';
 
 //// [c.ts]
-export type * as ns from './a'; // Grammar error
+export type * as ns from './a';
 
 //// [d.ts]
 import { A } from './b';
@@ -41,5 +41,4 @@ A;
 //// [e.js]
 "use strict";
 Object.defineProperty(exports, "__esModule", { value: true });
-var c_1 = require("./c");
-c_1.ns.A;
+ns.A;
diff --git a/tests/baselines/reference/exportNamespace4.symbols b/tests/baselines/reference/exportNamespace4.symbols
index 7e4d3712c41d9..aed58d785648d 100644
--- a/tests/baselines/reference/exportNamespace4.symbols
+++ b/tests/baselines/reference/exportNamespace4.symbols
@@ -4,10 +4,10 @@ export class A {}
 
 === tests/cases/conformance/externalModules/typeOnly/b.ts ===
 
-export type * from './a'; // Grammar error
+export type * from './a';
 
 === tests/cases/conformance/externalModules/typeOnly/c.ts ===
-export type * as ns from './a'; // Grammar error
+export type * as ns from './a';
 >ns : Symbol(ns, Decl(c.ts, 0, 11))
 
 === tests/cases/conformance/externalModules/typeOnly/d.ts ===
diff --git a/tests/baselines/reference/exportNamespace4.types b/tests/baselines/reference/exportNamespace4.types
index d1a496dad809d..397948eae7ca6 100644
--- a/tests/baselines/reference/exportNamespace4.types
+++ b/tests/baselines/reference/exportNamespace4.types
@@ -4,10 +4,10 @@ export class A {}
 
 === tests/cases/conformance/externalModules/typeOnly/b.ts ===
 
-export type * from './a'; // Grammar error
+export type * from './a';
 
 === tests/cases/conformance/externalModules/typeOnly/c.ts ===
-export type * as ns from './a'; // Grammar error
+export type * as ns from './a';
 >ns : typeof import("tests/cases/conformance/externalModules/typeOnly/a")
 
 === tests/cases/conformance/externalModules/typeOnly/d.ts ===
diff --git a/tests/cases/conformance/externalModules/typeOnly/exportNamespace4.ts b/tests/cases/conformance/externalModules/typeOnly/exportNamespace4.ts
index 889552e6643fe..1cf51dc69cba0 100644
--- a/tests/cases/conformance/externalModules/typeOnly/exportNamespace4.ts
+++ b/tests/cases/conformance/externalModules/typeOnly/exportNamespace4.ts
@@ -2,10 +2,10 @@
 export class A {}
 
 // @Filename: b.ts
-export type * from './a'; // Grammar error
+export type * from './a';
 
 // @Filename: c.ts
-export type * as ns from './a'; // Grammar error
+export type * as ns from './a';
 
 // @Filename: d.ts
 import { A } from './b';

From 3b6a1854b4b49ef91bc41369d938af1af4359752 Mon Sep 17 00:00:00 2001
From: Andrew Branch <andrew@wheream.io>
Date: Thu, 12 Jan 2023 15:41:13 -0800
Subject: [PATCH 6/8] Update diagnostic baseline

---
 .../tsserver/plugins/getSupportedCodeFixes-can-be-proxied.js   | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/tests/baselines/reference/tsserver/plugins/getSupportedCodeFixes-can-be-proxied.js b/tests/baselines/reference/tsserver/plugins/getSupportedCodeFixes-can-be-proxied.js
index eaf791e9d05d7..252ccc4e6c1fc 100644
--- a/tests/baselines/reference/tsserver/plugins/getSupportedCodeFixes-can-be-proxied.js
+++ b/tests/baselines/reference/tsserver/plugins/getSupportedCodeFixes-can-be-proxied.js
@@ -678,7 +678,6 @@ Info 32   [00:01:13.000] response:
         "1368",
         "1379",
         "1380",
-        "1383",
         "1385",
         "1386",
         "1387",
@@ -2012,7 +2011,6 @@ Info 38   [00:01:19.000] response:
         "1368",
         "1379",
         "1380",
-        "1383",
         "1385",
         "1386",
         "1387",
@@ -3258,7 +3256,6 @@ Info 40   [00:01:21.000] response:
         "1368",
         "1379",
         "1380",
-        "1383",
         "1385",
         "1386",
         "1387",

From 4a5917b254059c5b20038f0e0d0fb46d28de7e18 Mon Sep 17 00:00:00 2001
From: Andrew Branch <andrew@wheream.io>
Date: Thu, 19 Jan 2023 11:41:37 -0800
Subject: [PATCH 7/8] Add declaration emit to baselines, verify syntax is an
 error in JS

---
 tests/baselines/reference/exportNamespace4.js | 13 ++++++
 tests/baselines/reference/exportNamespace5.js | 19 +++++++++
 .../reference/exportNamespace_js.errors.txt   | 19 +++++++++
 .../baselines/reference/exportNamespace_js.js | 40 +++++++++++++++++++
 .../reference/exportNamespace_js.symbols      | 15 +++++++
 .../reference/exportNamespace_js.types        | 15 +++++++
 .../typeOnly/exportNamespace4.ts              |  2 +
 .../typeOnly/exportNamespace5.ts              |  2 +
 .../typeOnly/exportNamespace_js.ts            | 14 +++++++
 9 files changed, 139 insertions(+)
 create mode 100644 tests/baselines/reference/exportNamespace_js.errors.txt
 create mode 100644 tests/baselines/reference/exportNamespace_js.js
 create mode 100644 tests/baselines/reference/exportNamespace_js.symbols
 create mode 100644 tests/baselines/reference/exportNamespace_js.types
 create mode 100644 tests/cases/conformance/externalModules/typeOnly/exportNamespace_js.ts

diff --git a/tests/baselines/reference/exportNamespace4.js b/tests/baselines/reference/exportNamespace4.js
index faa416399761b..fa6b5d9372097 100644
--- a/tests/baselines/reference/exportNamespace4.js
+++ b/tests/baselines/reference/exportNamespace4.js
@@ -42,3 +42,16 @@ A;
 "use strict";
 Object.defineProperty(exports, "__esModule", { value: true });
 ns.A;
+
+
+//// [a.d.ts]
+export declare class A {
+}
+//// [b.d.ts]
+export type * from './a';
+//// [c.d.ts]
+export type * as ns from './a';
+//// [d.d.ts]
+export {};
+//// [e.d.ts]
+export {};
diff --git a/tests/baselines/reference/exportNamespace5.js b/tests/baselines/reference/exportNamespace5.js
index ae61f9da7236d..a1ec261fa8b80 100644
--- a/tests/baselines/reference/exportNamespace5.js
+++ b/tests/baselines/reference/exportNamespace5.js
@@ -85,3 +85,22 @@ var d_1 = require("./d");
 var _ = new d_1.A(); // Ok
 var __ = new d_1.B(); // Ok
 var ___ = new d_1.X(); // Ok
+
+
+//// [a.d.ts]
+export declare class A {
+}
+export declare class B {
+}
+export declare class X {
+}
+//// [b.d.ts]
+export type * from "./a";
+export { X } from "./a";
+//// [c.d.ts]
+export {};
+//// [d.d.ts]
+export type * from "./a";
+export * from "./a";
+//// [e.d.ts]
+export {};
diff --git a/tests/baselines/reference/exportNamespace_js.errors.txt b/tests/baselines/reference/exportNamespace_js.errors.txt
new file mode 100644
index 0000000000000..32764f3e57c3e
--- /dev/null
+++ b/tests/baselines/reference/exportNamespace_js.errors.txt
@@ -0,0 +1,19 @@
+tests/cases/conformance/externalModules/typeOnly/b.js(1,1): error TS8006: 'export type' declarations can only be used in TypeScript files.
+tests/cases/conformance/externalModules/typeOnly/c.js(2,1): error TS1362: 'A' cannot be used as a value because it was exported using 'export type'.
+
+
+==== tests/cases/conformance/externalModules/typeOnly/a.js (0 errors) ====
+    export class A {}
+    
+==== tests/cases/conformance/externalModules/typeOnly/b.js (1 errors) ====
+    export type * from './a';
+    ~~~~~~~~~~~~~~~~~~~~~~~~~
+!!! error TS8006: 'export type' declarations can only be used in TypeScript files.
+    
+==== tests/cases/conformance/externalModules/typeOnly/c.js (1 errors) ====
+    import { A } from './b';
+    A;
+    ~
+!!! error TS1362: 'A' cannot be used as a value because it was exported using 'export type'.
+!!! related TS1377 tests/cases/conformance/externalModules/typeOnly/b.js:1:1: 'A' was exported here.
+    
\ No newline at end of file
diff --git a/tests/baselines/reference/exportNamespace_js.js b/tests/baselines/reference/exportNamespace_js.js
new file mode 100644
index 0000000000000..95e8c9e059702
--- /dev/null
+++ b/tests/baselines/reference/exportNamespace_js.js
@@ -0,0 +1,40 @@
+//// [tests/cases/conformance/externalModules/typeOnly/exportNamespace_js.ts] ////
+
+//// [a.js]
+export class A {}
+
+//// [b.js]
+export type * from './a';
+
+//// [c.js]
+import { A } from './b';
+A;
+
+
+//// [a.js]
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.A = void 0;
+var A = /** @class */ (function () {
+    function A() {
+    }
+    return A;
+}());
+exports.A = A;
+//// [b.js]
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+//// [c.js]
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+var b_1 = require("./b");
+A;
+
+
+//// [a.d.ts]
+export class A {
+}
+//// [b.d.ts]
+export * from "./a";
+//// [c.d.ts]
+export {};
diff --git a/tests/baselines/reference/exportNamespace_js.symbols b/tests/baselines/reference/exportNamespace_js.symbols
new file mode 100644
index 0000000000000..475710b68489e
--- /dev/null
+++ b/tests/baselines/reference/exportNamespace_js.symbols
@@ -0,0 +1,15 @@
+=== tests/cases/conformance/externalModules/typeOnly/a.js ===
+export class A {}
+>A : Symbol(A, Decl(a.js, 0, 0))
+
+=== tests/cases/conformance/externalModules/typeOnly/b.js ===
+
+export type * from './a';
+
+=== tests/cases/conformance/externalModules/typeOnly/c.js ===
+import { A } from './b';
+>A : Symbol(A, Decl(c.js, 0, 8))
+
+A;
+>A : Symbol(A, Decl(c.js, 0, 8))
+
diff --git a/tests/baselines/reference/exportNamespace_js.types b/tests/baselines/reference/exportNamespace_js.types
new file mode 100644
index 0000000000000..3205448594836
--- /dev/null
+++ b/tests/baselines/reference/exportNamespace_js.types
@@ -0,0 +1,15 @@
+=== tests/cases/conformance/externalModules/typeOnly/a.js ===
+export class A {}
+>A : A
+
+=== tests/cases/conformance/externalModules/typeOnly/b.js ===
+
+export type * from './a';
+
+=== tests/cases/conformance/externalModules/typeOnly/c.js ===
+import { A } from './b';
+>A : typeof A
+
+A;
+>A : typeof A
+
diff --git a/tests/cases/conformance/externalModules/typeOnly/exportNamespace4.ts b/tests/cases/conformance/externalModules/typeOnly/exportNamespace4.ts
index 1cf51dc69cba0..1cb1c1f0d9539 100644
--- a/tests/cases/conformance/externalModules/typeOnly/exportNamespace4.ts
+++ b/tests/cases/conformance/externalModules/typeOnly/exportNamespace4.ts
@@ -1,3 +1,5 @@
+// @declaration: true
+
 // @Filename: a.ts
 export class A {}
 
diff --git a/tests/cases/conformance/externalModules/typeOnly/exportNamespace5.ts b/tests/cases/conformance/externalModules/typeOnly/exportNamespace5.ts
index c085d6ced438c..fd4d392fb589f 100644
--- a/tests/cases/conformance/externalModules/typeOnly/exportNamespace5.ts
+++ b/tests/cases/conformance/externalModules/typeOnly/exportNamespace5.ts
@@ -1,3 +1,5 @@
+// @declaration: true
+
 // @Filename: /a.ts
 export class A {}
 export class B {}
diff --git a/tests/cases/conformance/externalModules/typeOnly/exportNamespace_js.ts b/tests/cases/conformance/externalModules/typeOnly/exportNamespace_js.ts
new file mode 100644
index 0000000000000..3e02cecc306de
--- /dev/null
+++ b/tests/cases/conformance/externalModules/typeOnly/exportNamespace_js.ts
@@ -0,0 +1,14 @@
+// @declaration: true
+// @outDir: out
+// @checkJs: true
+// @allowJs: true
+
+// @Filename: a.js
+export class A {}
+
+// @Filename: b.js
+export type * from './a';
+
+// @Filename: c.js
+import { A } from './b';
+A;

From 271418fa714b93a0ff5826b7171b949dcb8d6acc Mon Sep 17 00:00:00 2001
From: Andrew Branch <andrew@wheream.io>
Date: Fri, 20 Jan 2023 13:31:14 -0800
Subject: [PATCH 8/8] Preserve `type` in dts even when it came from JS

---
 src/compiler/checker.ts                         | 2 +-
 tests/baselines/reference/exportNamespace_js.js | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts
index b47ae45f0351f..d20aca210332f 100644
--- a/src/compiler/checker.ts
+++ b/src/compiler/checker.ts
@@ -8553,7 +8553,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
                         for (const node of symbol.declarations) {
                             const resolvedModule = resolveExternalModuleName(node, (node as ExportDeclaration).moduleSpecifier!);
                             if (!resolvedModule) continue;
-                            addResult(factory.createExportDeclaration(/*modifiers*/ undefined, /*isTypeOnly*/ false, /*exportClause*/ undefined, factory.createStringLiteral(getSpecifierForModuleSymbol(resolvedModule, context))), ModifierFlags.None);
+                            addResult(factory.createExportDeclaration(/*modifiers*/ undefined, /*isTypeOnly*/ (node as ExportDeclaration).isTypeOnly, /*exportClause*/ undefined, factory.createStringLiteral(getSpecifierForModuleSymbol(resolvedModule, context))), ModifierFlags.None);
                         }
                     }
                 }
diff --git a/tests/baselines/reference/exportNamespace_js.js b/tests/baselines/reference/exportNamespace_js.js
index 95e8c9e059702..4e64bdc174398 100644
--- a/tests/baselines/reference/exportNamespace_js.js
+++ b/tests/baselines/reference/exportNamespace_js.js
@@ -35,6 +35,6 @@ A;
 export class A {
 }
 //// [b.d.ts]
-export * from "./a";
+export type * from "./a";
 //// [c.d.ts]
 export {};