diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts
index 80b61edd3657a..37d8fc4725c93 100644
--- a/src/compiler/checker.ts
+++ b/src/compiler/checker.ts
@@ -640,6 +640,7 @@ import {
isJsxCallLike,
isJsxElement,
isJsxFragment,
+ isJsxIntrinsicTagName,
isJsxNamespacedName,
isJsxOpeningElement,
isJsxOpeningFragment,
@@ -833,7 +834,6 @@ import {
JsxExpression,
JsxFlags,
JsxFragment,
- JsxNamespacedName,
JsxOpeningElement,
JsxOpeningFragment,
JsxOpeningLikeElement,
@@ -33099,13 +33099,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
return (name as string).includes("-");
}
- /**
- * Returns true iff React would emit this tag name as a string rather than an identifier or qualified name
- */
- function isJsxIntrinsicTagName(tagName: Node): tagName is Identifier | JsxNamespacedName {
- return isIdentifier(tagName) && isIntrinsicJsxName(tagName.escapedText) || isJsxNamespacedName(tagName);
- }
-
function checkJsxAttribute(node: JsxAttribute, checkMode?: CheckMode) {
return node.initializer
? checkExpressionForMutableLocation(node.initializer, checkMode)
diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts
index 75656cf5aefab..5ba6307851bcb 100644
--- a/src/compiler/transformers/ts.ts
+++ b/src/compiler/transformers/ts.ts
@@ -103,6 +103,8 @@ import {
isInstantiatedModule,
isJsonSourceFile,
isJsxAttributes,
+ isJsxIntrinsicTagName,
+ isJSXTagName,
isJsxTagNameExpression,
isLeftHandSideExpression,
isLocalName,
@@ -2688,8 +2690,10 @@ export function transformTypeScript(context: TransformationContext): Transformer
// an identifier that is exported from a merged namespace.
const container = resolver.getReferencedExportContainer(node, /*prefixLocals*/ false);
if (container && container.kind !== SyntaxKind.SourceFile) {
- const substitute = (applicableSubstitutions & TypeScriptSubstitutionFlags.NamespaceExports && container.kind === SyntaxKind.ModuleDeclaration) ||
- (applicableSubstitutions & TypeScriptSubstitutionFlags.NonQualifiedEnumMembers && container.kind === SyntaxKind.EnumDeclaration);
+ let originalNode;
+ const substitute = ((applicableSubstitutions & TypeScriptSubstitutionFlags.NamespaceExports && container.kind === SyntaxKind.ModuleDeclaration) ||
+ (applicableSubstitutions & TypeScriptSubstitutionFlags.NonQualifiedEnumMembers && container.kind === SyntaxKind.EnumDeclaration)) &&
+ (!isJSXTagName(originalNode = getOriginalNode(node, isIdentifier)) || !isJsxIntrinsicTagName(originalNode));
if (substitute) {
return setTextRange(
factory.createPropertyAccessExpression(factory.getGeneratedNameForNode(container), node),
diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts
index 1ff3a2acada46..3af5393760c2d 100644
--- a/src/compiler/utilities.ts
+++ b/src/compiler/utilities.ts
@@ -3549,6 +3549,14 @@ export function isJSXTagName(node: Node): boolean {
return false;
}
+/**
+ * @internal
+ * Returns true if React would emit this tag name as a string rather than an identifier or qualified name
+ */
+export function isJsxIntrinsicTagName(tagName: Node): tagName is Identifier | JsxNamespacedName {
+ return isIdentifier(tagName) && isIntrinsicJsxName(tagName.escapedText) || isJsxNamespacedName(tagName);
+}
+
/** @internal */
export function isExpressionNode(node: Node): boolean {
switch (node.kind) {
diff --git a/tests/baselines/reference/namespaceJsxPreserve1.js b/tests/baselines/reference/namespaceJsxPreserve1.js
new file mode 100644
index 0000000000000..d9152e1f9de25
--- /dev/null
+++ b/tests/baselines/reference/namespaceJsxPreserve1.js
@@ -0,0 +1,27 @@
+//// [tests/cases/compiler/namespaceJsxPreserve1.tsx] ////
+
+//// [namespaceJsxPreserve1.tsx]
+///