| undefined;
var { enter: enterComment, exit: exitComment } = performance.createTimerIf(extendedDiagnostics, "commentTime", "beforeComment", "afterComment");
@@ -1389,11 +1389,22 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
currentSourceFile = sourceFile;
currentLineMap = undefined;
detachedCommentsInfo = undefined;
+ jsxTextRanges = []; // Clear JSX text ranges for new source file
+
+ // Pre-collect all JSX text ranges before emission starts
if (sourceFile) {
+ collectJsxTextRanges(sourceFile);
setSourceMapSource(sourceFile);
}
}
+ function collectJsxTextRanges(node: Node) {
+ if (node.kind === SyntaxKind.JsxText) {
+ jsxTextRanges.push({ start: node.pos, end: node.end });
+ }
+ forEachChild(node, collectJsxTextRanges);
+ }
+
function setWriter(_writer: EmitTextWriter | undefined, _sourceMapGenerator: SourceMapGenerator | undefined) {
if (_writer && printerOptions.omitTrailingSemicolon) {
_writer = getTrailingSemicolonDeferringWriter(_writer);
@@ -3860,14 +3871,9 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
//
function emitJsxElement(node: JsxElement) {
- const savedJsxElement = currentJsxElement;
- currentJsxElement = node;
-
emit(node.openingElement);
emitList(node, node.children, ListFormat.JsxElementOrFragmentChildren);
emit(node.closingElement);
-
- currentJsxElement = savedJsxElement;
}
function emitJsxSelfClosingElement(node: JsxSelfClosingElement) {
@@ -6103,31 +6109,27 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
forEachLeadingCommentWithoutDetachedComments(cb);
}
else {
- forEachLeadingCommentRange(currentSourceFile.text, pos, cb, /*state*/ pos);
+ forEachLeadingCommentRange(currentSourceFile.text, pos, (commentPos, commentEnd, kind, hasTrailingNewLine, rangePos) => {
+ // Check if this comment position falls within any JSX text range
+ const isWithinJsxText = jsxTextRanges.some(range => commentPos >= range.start && commentEnd <= range.end);
+ if (!isWithinJsxText) {
+ cb(commentPos, commentEnd, kind, hasTrailingNewLine, rangePos);
+ }
+ }, /*state*/ pos);
}
}
}
function forEachTrailingCommentToEmit(end: number, cb: (commentPos: number, commentEnd: number, kind: SyntaxKind, hasTrailingNewLine: boolean) => void) {
// Emit the trailing comments only if the container's end doesn't match because the container should take care of emitting these comments
-
- // Check if this position is within a JSX element that contains comment-only text children
- // If so, skip emission as the JSX processor will handle these comments
- if (currentJsxElement && end >= currentJsxElement.pos && end <= currentJsxElement.end) {
- // Check if any of the JSX children are comment-only text nodes
- const hasCommentOnlyText = currentJsxElement.children.some(child => {
- if (child.kind === SyntaxKind.JsxText) {
- return child.text.trim().startsWith("/*") && child.text.trim().endsWith("*/");
+ if (currentSourceFile && (containerEnd === -1 || (end !== containerEnd && end !== declarationListContainerEnd))) {
+ forEachTrailingCommentRange(currentSourceFile.text, end, (commentPos, commentEnd, kind, hasTrailingNewLine) => {
+ // Check if this comment position falls within any JSX text range
+ const isWithinJsxText = jsxTextRanges.some(range => commentPos >= range.start && commentEnd <= range.end);
+ if (!isWithinJsxText) {
+ cb(commentPos, commentEnd, kind, hasTrailingNewLine);
}
- return false;
});
- if (hasCommentOnlyText) {
- return; // Skip comment emission - will be handled by JSX processing
- }
- }
-
- if (currentSourceFile && (containerEnd === -1 || (end !== containerEnd && end !== declarationListContainerEnd))) {
- forEachTrailingCommentRange(currentSourceFile.text, end, cb);
}
}
@@ -6146,7 +6148,13 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
detachedCommentsInfo = undefined;
}
- forEachLeadingCommentRange(currentSourceFile.text, pos, cb, /*state*/ pos);
+ forEachLeadingCommentRange(currentSourceFile.text, pos, (commentPos, commentEnd, kind, hasTrailingNewLine, rangePos) => {
+ // Check if this comment position falls within any JSX text range
+ const isWithinJsxText = jsxTextRanges.some(range => commentPos >= range.start && commentEnd <= range.end);
+ if (!isWithinJsxText) {
+ cb(commentPos, commentEnd, kind, hasTrailingNewLine, rangePos);
+ }
+ }, /*state*/ pos);
}
function emitDetachedCommentsAndUpdateCommentsInfo(range: TextRange) {
diff --git a/tests/baselines/reference/jsxCommentDuplication.js b/tests/baselines/reference/jsxCommentDuplication.js
index 42cf5304a7a95..15426054ad301 100644
--- a/tests/baselines/reference/jsxCommentDuplication.js
+++ b/tests/baselines/reference/jsxCommentDuplication.js
@@ -6,4 +6,4 @@ const jsx = /* no */{/* 1 */ 123 /* 2 */}/* no */;
//// [jsxCommentDuplication.jsx]
function App() { }
-var jsx = /* no */{123}/* no */;
+var jsx = /* no */{/* 1 */123 /* 2 */}/* no */;
diff --git a/tests/baselines/reference/tsxAttributeResolution14.js b/tests/baselines/reference/tsxAttributeResolution14.js
index 26633239d3918..1d20896a73dd7 100644
--- a/tests/baselines/reference/tsxAttributeResolution14.js
+++ b/tests/baselines/reference/tsxAttributeResolution14.js
@@ -35,11 +35,8 @@ function VerticalNavMenuItem(prop) {
}
function VerticalNav() {
return (
- // error
- // error
- // ok
- // ok
- // error
- // error
+ // error
+ // ok
+ // error
);
}
From 381423f459117fdd67b6fec0aa334a32246da81f Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sat, 28 Jun 2025 07:35:59 +0000
Subject: [PATCH 7/8] Add question about JSX comment handling to documentation
Co-authored-by: RyanCavanaugh <6685088+RyanCavanaugh@users.noreply.github.com>
---
.github/copilot-questions.md | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/.github/copilot-questions.md b/.github/copilot-questions.md
index 250d4bf2d776d..d9c9c74a0afa8 100644
--- a/.github/copilot-questions.md
+++ b/.github/copilot-questions.md
@@ -1,4 +1,5 @@
-Questions I have that I think the developers of this project can help me with:
- * How does control flow analysis represent a circular graph? I checked the documentation server for "cfa" and "control flow"
- * How do I tell if a symbol is in the global scope? I checked the documentation server for topics referencing "symbol" and "global"
- * What is an `EscapedName`, exactly?
+Questions I have that I think the developers of this project can help me with:
+ * How does control flow analysis represent a circular graph? I checked the documentation server for "cfa" and "control flow"
+ * How do I tell if a symbol is in the global scope? I checked the documentation server for topics referencing "symbol" and "global"
+ * What is an `EscapedName`, exactly?
+ * How does TypeScript distinguish between comments inside JSX text vs regular TypeScript comments? I searched for "JSX text comments emitter forEachTrailingCommentRange JSX text ranges" - The issue was that comment iteration doesn't understand JSX context and treats JSX text content as regular comments.
From 93c7172440813d8050b01f3ff583dd4067b79fd2 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sat, 28 Jun 2025 16:49:35 +0000
Subject: [PATCH 8/8] Improve JSX comment duplication fix - use targeted node
traversal instead of expensive pre-walk
Co-authored-by: RyanCavanaugh <6685088+RyanCavanaugh@users.noreply.github.com>
---
src/compiler/emitter.ts | 63 ++++++++++++-------
.../jsxCommentDuplication(jsx=preserve).js | 9 +++
...sxCommentDuplication(jsx=preserve).symbols | 11 ++++
.../jsxCommentDuplication(jsx=preserve).types | 17 +++++
...sxCommentDuplication(jsx=react).errors.txt | 8 +++
.../jsxCommentDuplication(jsx=react).js | 12 ++++
.../jsxCommentDuplication(jsx=react).symbols | 11 ++++
.../jsxCommentDuplication(jsx=react).types | 19 ++++++
...mmentDuplication(jsx=react-jsx).errors.txt | 8 +++
.../jsxCommentDuplication(jsx=react-jsx).js | 12 ++++
...xCommentDuplication(jsx=react-jsx).symbols | 11 ++++
...jsxCommentDuplication(jsx=react-jsx).types | 19 ++++++
.../cases/compiler/jsxCommentDuplication.tsx | 2 +-
13 files changed, 180 insertions(+), 22 deletions(-)
create mode 100644 tests/baselines/reference/jsxCommentDuplication(jsx=preserve).js
create mode 100644 tests/baselines/reference/jsxCommentDuplication(jsx=preserve).symbols
create mode 100644 tests/baselines/reference/jsxCommentDuplication(jsx=preserve).types
create mode 100644 tests/baselines/reference/jsxCommentDuplication(jsx=react).errors.txt
create mode 100644 tests/baselines/reference/jsxCommentDuplication(jsx=react).js
create mode 100644 tests/baselines/reference/jsxCommentDuplication(jsx=react).symbols
create mode 100644 tests/baselines/reference/jsxCommentDuplication(jsx=react).types
create mode 100644 tests/baselines/reference/jsxCommentDuplication(jsx=react-jsx).errors.txt
create mode 100644 tests/baselines/reference/jsxCommentDuplication(jsx=react-jsx).js
create mode 100644 tests/baselines/reference/jsxCommentDuplication(jsx=react-jsx).symbols
create mode 100644 tests/baselines/reference/jsxCommentDuplication(jsx=react-jsx).types
diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts
index dee6758ef1559..e6c55e11e45d8 100644
--- a/src/compiler/emitter.ts
+++ b/src/compiler/emitter.ts
@@ -1253,8 +1253,7 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
var detachedCommentsInfo: { nodePos: number; detachedCommentEndPos: number; }[] | undefined;
var hasWrittenComment = false;
var commentsDisabled = !!printerOptions.removeComments;
- // Track JSX text ranges to prevent them from being treated as comments
- var jsxTextRanges: { start: number; end: number; }[] = [];
+ var jsxTextPositionCache: Map | undefined;
var lastSubstitution: Node | undefined;
var currentParenthesizerRule: ParenthesizerRule | undefined;
var { enter: enterComment, exit: exitComment } = performance.createTimerIf(extendedDiagnostics, "commentTime", "beforeComment", "afterComment");
@@ -1389,22 +1388,13 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
currentSourceFile = sourceFile;
currentLineMap = undefined;
detachedCommentsInfo = undefined;
- jsxTextRanges = []; // Clear JSX text ranges for new source file
+ jsxTextPositionCache = undefined; // Clear cache for new source file
- // Pre-collect all JSX text ranges before emission starts
if (sourceFile) {
- collectJsxTextRanges(sourceFile);
setSourceMapSource(sourceFile);
}
}
- function collectJsxTextRanges(node: Node) {
- if (node.kind === SyntaxKind.JsxText) {
- jsxTextRanges.push({ start: node.pos, end: node.end });
- }
- forEachChild(node, collectJsxTextRanges);
- }
-
function setWriter(_writer: EmitTextWriter | undefined, _sourceMapGenerator: SourceMapGenerator | undefined) {
if (_writer && printerOptions.omitTrailingSemicolon) {
_writer = getTrailingSemicolonDeferringWriter(_writer);
@@ -1415,6 +1405,40 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
sourceMapsDisabled = !writer || !sourceMapGenerator;
}
+ function isPositionInJsxText(pos: number): boolean {
+ if (!currentSourceFile) return false;
+
+ // Use cache if available
+ if (!jsxTextPositionCache) {
+ jsxTextPositionCache = new Map();
+ }
+
+ if (jsxTextPositionCache.has(pos)) {
+ return jsxTextPositionCache.get(pos)!;
+ }
+
+ // Walk the AST to find if this position is within a JSX text node
+ let found = false;
+
+ function visitNode(node: Node): void {
+ if (found) return;
+
+ if (node.kind === SyntaxKind.JsxText && pos >= node.pos && pos < node.end) {
+ found = true;
+ return;
+ }
+
+ // Only continue traversing if this node might contain the position
+ if (pos >= node.pos && pos < node.end) {
+ forEachChild(node, visitNode);
+ }
+ }
+
+ visitNode(currentSourceFile);
+ jsxTextPositionCache.set(pos, found);
+ return found;
+ }
+
function reset() {
nodeIdToGeneratedName = [];
nodeIdToGeneratedPrivateName = [];
@@ -6110,9 +6134,8 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
}
else {
forEachLeadingCommentRange(currentSourceFile.text, pos, (commentPos, commentEnd, kind, hasTrailingNewLine, rangePos) => {
- // Check if this comment position falls within any JSX text range
- const isWithinJsxText = jsxTextRanges.some(range => commentPos >= range.start && commentEnd <= range.end);
- if (!isWithinJsxText) {
+ // Skip comments that are within JSX text nodes
+ if (!isPositionInJsxText(commentPos)) {
cb(commentPos, commentEnd, kind, hasTrailingNewLine, rangePos);
}
}, /*state*/ pos);
@@ -6124,9 +6147,8 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
// Emit the trailing comments only if the container's end doesn't match because the container should take care of emitting these comments
if (currentSourceFile && (containerEnd === -1 || (end !== containerEnd && end !== declarationListContainerEnd))) {
forEachTrailingCommentRange(currentSourceFile.text, end, (commentPos, commentEnd, kind, hasTrailingNewLine) => {
- // Check if this comment position falls within any JSX text range
- const isWithinJsxText = jsxTextRanges.some(range => commentPos >= range.start && commentEnd <= range.end);
- if (!isWithinJsxText) {
+ // Skip comments that are within JSX text nodes
+ if (!isPositionInJsxText(commentPos)) {
cb(commentPos, commentEnd, kind, hasTrailingNewLine);
}
});
@@ -6149,9 +6171,8 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
}
forEachLeadingCommentRange(currentSourceFile.text, pos, (commentPos, commentEnd, kind, hasTrailingNewLine, rangePos) => {
- // Check if this comment position falls within any JSX text range
- const isWithinJsxText = jsxTextRanges.some(range => commentPos >= range.start && commentEnd <= range.end);
- if (!isWithinJsxText) {
+ // Skip comments that are within JSX text nodes
+ if (!isPositionInJsxText(commentPos)) {
cb(commentPos, commentEnd, kind, hasTrailingNewLine, rangePos);
}
}, /*state*/ pos);
diff --git a/tests/baselines/reference/jsxCommentDuplication(jsx=preserve).js b/tests/baselines/reference/jsxCommentDuplication(jsx=preserve).js
new file mode 100644
index 0000000000000..15426054ad301
--- /dev/null
+++ b/tests/baselines/reference/jsxCommentDuplication(jsx=preserve).js
@@ -0,0 +1,9 @@
+//// [tests/cases/compiler/jsxCommentDuplication.tsx] ////
+
+//// [jsxCommentDuplication.tsx]
+function App() {}
+const jsx = /* no */{/* 1 */ 123 /* 2 */}/* no */;
+
+//// [jsxCommentDuplication.jsx]
+function App() { }
+var jsx = /* no */{/* 1 */123 /* 2 */}/* no */;
diff --git a/tests/baselines/reference/jsxCommentDuplication(jsx=preserve).symbols b/tests/baselines/reference/jsxCommentDuplication(jsx=preserve).symbols
new file mode 100644
index 0000000000000..328bd5542845d
--- /dev/null
+++ b/tests/baselines/reference/jsxCommentDuplication(jsx=preserve).symbols
@@ -0,0 +1,11 @@
+//// [tests/cases/compiler/jsxCommentDuplication.tsx] ////
+
+=== jsxCommentDuplication.tsx ===
+function App() {}
+>App : Symbol(App, Decl(jsxCommentDuplication.tsx, 0, 0))
+
+const jsx = /* no */{/* 1 */ 123 /* 2 */}/* no */;
+>jsx : Symbol(jsx, Decl(jsxCommentDuplication.tsx, 1, 5))
+>App : Symbol(App, Decl(jsxCommentDuplication.tsx, 0, 0))
+>App : Symbol(App, Decl(jsxCommentDuplication.tsx, 0, 0))
+
diff --git a/tests/baselines/reference/jsxCommentDuplication(jsx=preserve).types b/tests/baselines/reference/jsxCommentDuplication(jsx=preserve).types
new file mode 100644
index 0000000000000..5a4fbfe5078c4
--- /dev/null
+++ b/tests/baselines/reference/jsxCommentDuplication(jsx=preserve).types
@@ -0,0 +1,17 @@
+//// [tests/cases/compiler/jsxCommentDuplication.tsx] ////
+
+=== jsxCommentDuplication.tsx ===
+function App() {}
+>App : () => void
+> : ^^^^^^^^^^
+
+const jsx = /* no */{/* 1 */ 123 /* 2 */}/* no */;
+>jsx : error
+>/* no */{/* 1 */ 123 /* 2 */}/* no */ : error
+>App : () => void
+> : ^^^^^^^^^^
+>123 : 123
+> : ^^^
+>App : () => void
+> : ^^^^^^^^^^
+
diff --git a/tests/baselines/reference/jsxCommentDuplication(jsx=react).errors.txt b/tests/baselines/reference/jsxCommentDuplication(jsx=react).errors.txt
new file mode 100644
index 0000000000000..5902bb8f12f9e
--- /dev/null
+++ b/tests/baselines/reference/jsxCommentDuplication(jsx=react).errors.txt
@@ -0,0 +1,8 @@
+jsxCommentDuplication.tsx(2,14): error TS2874: This JSX tag requires 'React' to be in scope, but it could not be found.
+
+
+==== jsxCommentDuplication.tsx (1 errors) ====
+ function App() {}
+ const jsx = /* no */{/* 1 */ 123 /* 2 */}/* no */;
+ ~~~
+!!! error TS2874: This JSX tag requires 'React' to be in scope, but it could not be found.
\ No newline at end of file
diff --git a/tests/baselines/reference/jsxCommentDuplication(jsx=react).js b/tests/baselines/reference/jsxCommentDuplication(jsx=react).js
new file mode 100644
index 0000000000000..37cba9d576718
--- /dev/null
+++ b/tests/baselines/reference/jsxCommentDuplication(jsx=react).js
@@ -0,0 +1,12 @@
+//// [tests/cases/compiler/jsxCommentDuplication.tsx] ////
+
+//// [jsxCommentDuplication.tsx]
+function App() {}
+const jsx = /* no */{/* 1 */ 123 /* 2 */}/* no */;
+
+//// [jsxCommentDuplication.js]
+function App() { }
+var jsx = React.createElement(App, null,
+ "/* no */", /* 1 */
+ 123 /* 2 */,
+ "/* no */");
diff --git a/tests/baselines/reference/jsxCommentDuplication(jsx=react).symbols b/tests/baselines/reference/jsxCommentDuplication(jsx=react).symbols
new file mode 100644
index 0000000000000..328bd5542845d
--- /dev/null
+++ b/tests/baselines/reference/jsxCommentDuplication(jsx=react).symbols
@@ -0,0 +1,11 @@
+//// [tests/cases/compiler/jsxCommentDuplication.tsx] ////
+
+=== jsxCommentDuplication.tsx ===
+function App() {}
+>App : Symbol(App, Decl(jsxCommentDuplication.tsx, 0, 0))
+
+const jsx = /* no */{/* 1 */ 123 /* 2 */}/* no */;
+>jsx : Symbol(jsx, Decl(jsxCommentDuplication.tsx, 1, 5))
+>App : Symbol(App, Decl(jsxCommentDuplication.tsx, 0, 0))
+>App : Symbol(App, Decl(jsxCommentDuplication.tsx, 0, 0))
+
diff --git a/tests/baselines/reference/jsxCommentDuplication(jsx=react).types b/tests/baselines/reference/jsxCommentDuplication(jsx=react).types
new file mode 100644
index 0000000000000..d0333134fdd1c
--- /dev/null
+++ b/tests/baselines/reference/jsxCommentDuplication(jsx=react).types
@@ -0,0 +1,19 @@
+//// [tests/cases/compiler/jsxCommentDuplication.tsx] ////
+
+=== jsxCommentDuplication.tsx ===
+function App() {}
+>App : () => void
+> : ^^^^^^^^^^
+
+const jsx = /* no */{/* 1 */ 123 /* 2 */}/* no */;
+>jsx : any
+> : ^^^
+>/* no */{/* 1 */ 123 /* 2 */}/* no */ : any
+> : ^^^
+>App : () => void
+> : ^^^^^^^^^^
+>123 : 123
+> : ^^^
+>App : () => void
+> : ^^^^^^^^^^
+
diff --git a/tests/baselines/reference/jsxCommentDuplication(jsx=react-jsx).errors.txt b/tests/baselines/reference/jsxCommentDuplication(jsx=react-jsx).errors.txt
new file mode 100644
index 0000000000000..a821a45616d2d
--- /dev/null
+++ b/tests/baselines/reference/jsxCommentDuplication(jsx=react-jsx).errors.txt
@@ -0,0 +1,8 @@
+jsxCommentDuplication.tsx(2,13): error TS2875: This JSX tag requires the module path 'react/jsx-runtime' to exist, but none could be found. Make sure you have types for the appropriate package installed.
+
+
+==== jsxCommentDuplication.tsx (1 errors) ====
+ function App() {}
+ const jsx = /* no */{/* 1 */ 123 /* 2 */}/* no */;
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+!!! error TS2875: This JSX tag requires the module path 'react/jsx-runtime' to exist, but none could be found. Make sure you have types for the appropriate package installed.
\ No newline at end of file
diff --git a/tests/baselines/reference/jsxCommentDuplication(jsx=react-jsx).js b/tests/baselines/reference/jsxCommentDuplication(jsx=react-jsx).js
new file mode 100644
index 0000000000000..b28abc2eb3933
--- /dev/null
+++ b/tests/baselines/reference/jsxCommentDuplication(jsx=react-jsx).js
@@ -0,0 +1,12 @@
+//// [tests/cases/compiler/jsxCommentDuplication.tsx] ////
+
+//// [jsxCommentDuplication.tsx]
+function App() {}
+const jsx = /* no */{/* 1 */ 123 /* 2 */}/* no */;
+
+//// [jsxCommentDuplication.js]
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+var jsx_runtime_1 = require("react/jsx-runtime");
+function App() { }
+var jsx = (0, jsx_runtime_1.jsxs)(App, { children: ["/* no */", /* 1 */ 123 /* 2 */, "/* no */"] });
diff --git a/tests/baselines/reference/jsxCommentDuplication(jsx=react-jsx).symbols b/tests/baselines/reference/jsxCommentDuplication(jsx=react-jsx).symbols
new file mode 100644
index 0000000000000..328bd5542845d
--- /dev/null
+++ b/tests/baselines/reference/jsxCommentDuplication(jsx=react-jsx).symbols
@@ -0,0 +1,11 @@
+//// [tests/cases/compiler/jsxCommentDuplication.tsx] ////
+
+=== jsxCommentDuplication.tsx ===
+function App() {}
+>App : Symbol(App, Decl(jsxCommentDuplication.tsx, 0, 0))
+
+const jsx = /* no */{/* 1 */ 123 /* 2 */}/* no */;
+>jsx : Symbol(jsx, Decl(jsxCommentDuplication.tsx, 1, 5))
+>App : Symbol(App, Decl(jsxCommentDuplication.tsx, 0, 0))
+>App : Symbol(App, Decl(jsxCommentDuplication.tsx, 0, 0))
+
diff --git a/tests/baselines/reference/jsxCommentDuplication(jsx=react-jsx).types b/tests/baselines/reference/jsxCommentDuplication(jsx=react-jsx).types
new file mode 100644
index 0000000000000..d0333134fdd1c
--- /dev/null
+++ b/tests/baselines/reference/jsxCommentDuplication(jsx=react-jsx).types
@@ -0,0 +1,19 @@
+//// [tests/cases/compiler/jsxCommentDuplication.tsx] ////
+
+=== jsxCommentDuplication.tsx ===
+function App() {}
+>App : () => void
+> : ^^^^^^^^^^
+
+const jsx = /* no */{/* 1 */ 123 /* 2 */}/* no */;
+>jsx : any
+> : ^^^
+>/* no */{/* 1 */ 123 /* 2 */}/* no */ : any
+> : ^^^
+>App : () => void
+> : ^^^^^^^^^^
+>123 : 123
+> : ^^^
+>App : () => void
+> : ^^^^^^^^^^
+
diff --git a/tests/cases/compiler/jsxCommentDuplication.tsx b/tests/cases/compiler/jsxCommentDuplication.tsx
index fe13875536038..a46de1b2ac76b 100644
--- a/tests/cases/compiler/jsxCommentDuplication.tsx
+++ b/tests/cases/compiler/jsxCommentDuplication.tsx
@@ -1,3 +1,3 @@
-// @jsx: preserve
+// @jsx: preserve,react,react-jsx
function App() {}
const jsx = /* no */{/* 1 */ 123 /* 2 */}/* no */;
\ No newline at end of file