diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 0567712f11da3..80867d03760ec 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -21702,6 +21702,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { switch (child.kind) { case SyntaxKind.JsxExpression: // child is of the type of the expression + // empty JsxExpression ({/* comment */}) has no expression — skip it the same way + // getSemanticJsxChildren and checkJsxChildren do, so nameType indices stay aligned + if (!child.expression) { + break; + } return { errorNode: child, innerExpression: child.expression, nameType }; case SyntaxKind.JsxText: if (child.containsOnlyTriviaWhiteSpaces) { diff --git a/tests/baselines/reference/jsxCommentExpressionDoesNotStealErrorLocation.errors.txt b/tests/baselines/reference/jsxCommentExpressionDoesNotStealErrorLocation.errors.txt new file mode 100644 index 0000000000000..9233e89509557 --- /dev/null +++ b/tests/baselines/reference/jsxCommentExpressionDoesNotStealErrorLocation.errors.txt @@ -0,0 +1,50 @@ +index.tsx(17,5): error TS2322: Type '{ notAString: true; }' is not assignable to type 'string'. +index.tsx(18,5): error TS2322: Type 'Element' is not assignable to type 'string'. +index.tsx(23,5): error TS2322: Type '{ notAString: true; }' is not assignable to type 'string'. +index.tsx(24,5): error TS2322: Type 'Element' is not assignable to type 'string'. +index.tsx(28,10): error TS2745: This JSX tag's 'children' prop expects type 'string[]' which requires multiple children, but only a single child was provided. + + +==== index.tsx (5 errors) ==== + /// + import * as React from "react"; + + interface Props { + children: string[]; + } + + export function Comp(props: Props) { + return <>; + } + + declare const badValue: { notAString: true }; + + // Error should be on {badValue}, not on {/* */} + var a = + {/* */} + {badValue} + ~~~~~~~~~~ +!!! error TS2322: Type '{ notAString: true; }' is not assignable to type 'string'. +
+ ~~~~~~ +!!! error TS2322: Type 'Element' is not assignable to type 'string'. +
+ + // No comment before — error should also be on {badValue} + var b = + {badValue} + ~~~~~~~~~~ +!!! error TS2322: Type '{ notAString: true; }' is not assignable to type 'string'. +
+ ~~~~~~ +!!! error TS2322: Type 'Element' is not assignable to type 'string'. +
+ + // Comment after — should not affect error location + var c = + ~~~~ +!!! error TS2745: This JSX tag's 'children' prop expects type 'string[]' which requires multiple children, but only a single child was provided. + {badValue} + {/* */} + + \ No newline at end of file diff --git a/tests/baselines/reference/jsxCommentExpressionDoesNotStealErrorLocation.js b/tests/baselines/reference/jsxCommentExpressionDoesNotStealErrorLocation.js new file mode 100644 index 0000000000000..29aab70e7a783 --- /dev/null +++ b/tests/baselines/reference/jsxCommentExpressionDoesNotStealErrorLocation.js @@ -0,0 +1,52 @@ +//// [tests/cases/compiler/jsxCommentExpressionDoesNotStealErrorLocation.tsx] //// + +//// [index.tsx] +/// +import * as React from "react"; + +interface Props { + children: string[]; +} + +export function Comp(props: Props) { + return <>; +} + +declare const badValue: { notAString: true }; + +// Error should be on {badValue}, not on {/* */} +var a = + {/* */} + {badValue} +
+
+ +// No comment before — error should also be on {badValue} +var b = + {badValue} +
+
+ +// Comment after — should not affect error location +var c = + {badValue} + {/* */} + + + +//// [index.js] +/// +import * as React from "react"; +export function Comp(props) { + return React.createElement(React.Fragment, null); +} +// Error should be on {badValue}, not on {/* */} +var a = React.createElement(Comp, null, + badValue, + React.createElement("br", null)); +// No comment before — error should also be on {badValue} +var b = React.createElement(Comp, null, + badValue, + React.createElement("br", null)); +// Comment after — should not affect error location +var c = React.createElement(Comp, null, badValue); diff --git a/tests/baselines/reference/jsxCommentExpressionDoesNotStealErrorLocation.symbols b/tests/baselines/reference/jsxCommentExpressionDoesNotStealErrorLocation.symbols new file mode 100644 index 0000000000000..a8a096227203c --- /dev/null +++ b/tests/baselines/reference/jsxCommentExpressionDoesNotStealErrorLocation.symbols @@ -0,0 +1,67 @@ +//// [tests/cases/compiler/jsxCommentExpressionDoesNotStealErrorLocation.tsx] //// + +=== index.tsx === +/// +import * as React from "react"; +>React : Symbol(React, Decl(index.tsx, 1, 6)) + +interface Props { +>Props : Symbol(Props, Decl(index.tsx, 1, 31)) + + children: string[]; +>children : Symbol(Props.children, Decl(index.tsx, 3, 17)) +} + +export function Comp(props: Props) { +>Comp : Symbol(Comp, Decl(index.tsx, 5, 1)) +>props : Symbol(props, Decl(index.tsx, 7, 21)) +>Props : Symbol(Props, Decl(index.tsx, 1, 31)) + + return <>; +} + +declare const badValue: { notAString: true }; +>badValue : Symbol(badValue, Decl(index.tsx, 11, 13)) +>notAString : Symbol(notAString, Decl(index.tsx, 11, 25)) + +// Error should be on {badValue}, not on {/* */} +var a = +>a : Symbol(a, Decl(index.tsx, 14, 3)) +>Comp : Symbol(Comp, Decl(index.tsx, 5, 1)) + + {/* */} + {badValue} +>badValue : Symbol(badValue, Decl(index.tsx, 11, 13)) + +
+>br : Symbol(JSX.IntrinsicElements.br, Decl(react16.d.ts, 2533, 102)) + +
+>Comp : Symbol(Comp, Decl(index.tsx, 5, 1)) + +// No comment before — error should also be on {badValue} +var b = +>b : Symbol(b, Decl(index.tsx, 21, 3)) +>Comp : Symbol(Comp, Decl(index.tsx, 5, 1)) + + {badValue} +>badValue : Symbol(badValue, Decl(index.tsx, 11, 13)) + +
+>br : Symbol(JSX.IntrinsicElements.br, Decl(react16.d.ts, 2533, 102)) + +
+>Comp : Symbol(Comp, Decl(index.tsx, 5, 1)) + +// Comment after — should not affect error location +var c = +>c : Symbol(c, Decl(index.tsx, 27, 3)) +>Comp : Symbol(Comp, Decl(index.tsx, 5, 1)) + + {badValue} +>badValue : Symbol(badValue, Decl(index.tsx, 11, 13)) + + {/* */} + +>Comp : Symbol(Comp, Decl(index.tsx, 5, 1)) + diff --git a/tests/baselines/reference/jsxCommentExpressionDoesNotStealErrorLocation.types b/tests/baselines/reference/jsxCommentExpressionDoesNotStealErrorLocation.types new file mode 100644 index 0000000000000..f9980e37e8cbf --- /dev/null +++ b/tests/baselines/reference/jsxCommentExpressionDoesNotStealErrorLocation.types @@ -0,0 +1,104 @@ +//// [tests/cases/compiler/jsxCommentExpressionDoesNotStealErrorLocation.tsx] //// + +=== Performance Stats === +Assignability cache: 2,500 +Type Count: 10,000 +Instantiation count: 100,000 +Symbol count: 50,000 + +=== index.tsx === +/// +import * as React from "react"; +>React : typeof React +> : ^^^^^^^^^^^^ + +interface Props { + children: string[]; +>children : string[] +> : ^^^^^^^^ +} + +export function Comp(props: Props) { +>Comp : (props: Props) => JSX.Element +> : ^ ^^ ^^^^^^^^^^^^^^^^ +>props : Props +> : ^^^^^ + + return <>; +><> : JSX.Element +> : ^^^^^^^^^^^ +} + +declare const badValue: { notAString: true }; +>badValue : { notAString: true; } +> : ^^^^^^^^^^^^^^ ^^^ +>notAString : true +> : ^^^^ +>true : true +> : ^^^^ + +// Error should be on {badValue}, not on {/* */} +var a = +>a : JSX.Element +> : ^^^^^^^^^^^ +> {/* */} {badValue}
: JSX.Element +> : ^^^^^^^^^^^ +>Comp : (props: Props) => JSX.Element +> : ^ ^^ ^^^^^^^^^^^^^^^^ + + {/* */} + {badValue} +>badValue : { notAString: true; } +> : ^^^^^^^^^^^^^^ ^^^ + +
+>
: JSX.Element +> : ^^^^^^^^^^^ +>br : any +> : ^^^ + +
+>Comp : (props: Props) => JSX.Element +> : ^ ^^ ^^^^^^^^^^^^^^^^ + +// No comment before — error should also be on {badValue} +var b = +>b : JSX.Element +> : ^^^^^^^^^^^ +> {badValue}
: JSX.Element +> : ^^^^^^^^^^^ +>Comp : (props: Props) => JSX.Element +> : ^ ^^ ^^^^^^^^^^^^^^^^ + + {badValue} +>badValue : { notAString: true; } +> : ^^^^^^^^^^^^^^ ^^^ + +
+>
: JSX.Element +> : ^^^^^^^^^^^ +>br : any +> : ^^^ + +
+>Comp : (props: Props) => JSX.Element +> : ^ ^^ ^^^^^^^^^^^^^^^^ + +// Comment after — should not affect error location +var c = +>c : JSX.Element +> : ^^^^^^^^^^^ +> {badValue} {/* */} : JSX.Element +> : ^^^^^^^^^^^ +>Comp : (props: Props) => JSX.Element +> : ^ ^^ ^^^^^^^^^^^^^^^^ + + {badValue} +>badValue : { notAString: true; } +> : ^^^^^^^^^^^^^^ ^^^ + + {/* */} + +>Comp : (props: Props) => JSX.Element +> : ^ ^^ ^^^^^^^^^^^^^^^^ + diff --git a/tests/cases/compiler/jsxCommentExpressionDoesNotStealErrorLocation.tsx b/tests/cases/compiler/jsxCommentExpressionDoesNotStealErrorLocation.tsx new file mode 100644 index 0000000000000..ecddfe589ea9d --- /dev/null +++ b/tests/cases/compiler/jsxCommentExpressionDoesNotStealErrorLocation.tsx @@ -0,0 +1,35 @@ +// @target: es2015 +// @jsx: react +// @strict: true +// @filename: index.tsx +/// +import * as React from "react"; + +interface Props { + children: string[]; +} + +export function Comp(props: Props) { + return <>; +} + +declare const badValue: { notAString: true }; + +// Error should be on {badValue}, not on {/* */} +var a = + {/* */} + {badValue} +
+
+ +// No comment before — error should also be on {badValue} +var b = + {badValue} +
+
+ +// Comment after — should not affect error location +var c = + {badValue} + {/* */} +