From 274821eb8860cba5f01946c4b1751c3d73d38795 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Wed, 4 Oct 2023 20:15:43 +0200 Subject: [PATCH] Don't create children prop out of non-semantic JSX children (#55981) --- src/compiler/checker.ts | 2 +- ...sOnlyTriviaWhiteSpacesNotCountedAsChild.js | 34 +++++++++++++++ ...TriviaWhiteSpacesNotCountedAsChild.symbols | 43 +++++++++++++++++++ ...lyTriviaWhiteSpacesNotCountedAsChild.types | 38 ++++++++++++++++ ...ptyExpressionNotCountedAsChild2.errors.txt | 15 +++---- ...OnlyTriviaWhiteSpacesNotCountedAsChild.tsx | 23 ++++++++++ 6 files changed, 144 insertions(+), 11 deletions(-) create mode 100644 tests/baselines/reference/jsxContainsOnlyTriviaWhiteSpacesNotCountedAsChild.js create mode 100644 tests/baselines/reference/jsxContainsOnlyTriviaWhiteSpacesNotCountedAsChild.symbols create mode 100644 tests/baselines/reference/jsxContainsOnlyTriviaWhiteSpacesNotCountedAsChild.types create mode 100644 tests/cases/compiler/jsxContainsOnlyTriviaWhiteSpacesNotCountedAsChild.tsx diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 563ab57ccc801..d46b7d67c24b8 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -31261,7 +31261,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Handle children attribute const parent = openingLikeElement.parent.kind === SyntaxKind.JsxElement ? openingLikeElement.parent as JsxElement : undefined; // We have to check that openingElement of the parent is the one we are visiting as this may not be true for selfClosingElement - if (parent && parent.openingElement === openingLikeElement && parent.children.length > 0) { + if (parent && parent.openingElement === openingLikeElement && getSemanticJsxChildren(parent.children).length > 0) { const childrenTypes: Type[] = checkJsxChildren(parent, checkMode); if (!hasSpreadAnyType && jsxChildrenPropertyName && jsxChildrenPropertyName !== "") { diff --git a/tests/baselines/reference/jsxContainsOnlyTriviaWhiteSpacesNotCountedAsChild.js b/tests/baselines/reference/jsxContainsOnlyTriviaWhiteSpacesNotCountedAsChild.js new file mode 100644 index 0000000000000..163d4d1aa997f --- /dev/null +++ b/tests/baselines/reference/jsxContainsOnlyTriviaWhiteSpacesNotCountedAsChild.js @@ -0,0 +1,34 @@ +//// [tests/cases/compiler/jsxContainsOnlyTriviaWhiteSpacesNotCountedAsChild.tsx] //// + +//// [jsxContainsOnlyTriviaWhiteSpacesNotCountedAsChild.tsx] +namespace JSX { + export interface ElementChildrenAttribute { + children: {}; + } +} + +interface Props { + className?: string | undefined; +} + +function NoticeList(props: Props) { + return null; +} + + +; + + + +; + +//// [jsxContainsOnlyTriviaWhiteSpacesNotCountedAsChild.jsx] +"use strict"; +function NoticeList(props) { + return null; +} + +; + + +; diff --git a/tests/baselines/reference/jsxContainsOnlyTriviaWhiteSpacesNotCountedAsChild.symbols b/tests/baselines/reference/jsxContainsOnlyTriviaWhiteSpacesNotCountedAsChild.symbols new file mode 100644 index 0000000000000..d5db851faa2fe --- /dev/null +++ b/tests/baselines/reference/jsxContainsOnlyTriviaWhiteSpacesNotCountedAsChild.symbols @@ -0,0 +1,43 @@ +//// [tests/cases/compiler/jsxContainsOnlyTriviaWhiteSpacesNotCountedAsChild.tsx] //// + +=== jsxContainsOnlyTriviaWhiteSpacesNotCountedAsChild.tsx === +namespace JSX { +>JSX : Symbol(JSX, Decl(jsxContainsOnlyTriviaWhiteSpacesNotCountedAsChild.tsx, 0, 0)) + + export interface ElementChildrenAttribute { +>ElementChildrenAttribute : Symbol(ElementChildrenAttribute, Decl(jsxContainsOnlyTriviaWhiteSpacesNotCountedAsChild.tsx, 0, 15)) + + children: {}; +>children : Symbol(ElementChildrenAttribute.children, Decl(jsxContainsOnlyTriviaWhiteSpacesNotCountedAsChild.tsx, 1, 45)) + } +} + +interface Props { +>Props : Symbol(Props, Decl(jsxContainsOnlyTriviaWhiteSpacesNotCountedAsChild.tsx, 4, 1)) + + className?: string | undefined; +>className : Symbol(Props.className, Decl(jsxContainsOnlyTriviaWhiteSpacesNotCountedAsChild.tsx, 6, 17)) +} + +function NoticeList(props: Props) { +>NoticeList : Symbol(NoticeList, Decl(jsxContainsOnlyTriviaWhiteSpacesNotCountedAsChild.tsx, 8, 1)) +>props : Symbol(props, Decl(jsxContainsOnlyTriviaWhiteSpacesNotCountedAsChild.tsx, 10, 20)) +>Props : Symbol(Props, Decl(jsxContainsOnlyTriviaWhiteSpacesNotCountedAsChild.tsx, 4, 1)) + + return null; +} + + +>NoticeList : Symbol(NoticeList, Decl(jsxContainsOnlyTriviaWhiteSpacesNotCountedAsChild.tsx, 8, 1)) +>className : Symbol(className, Decl(jsxContainsOnlyTriviaWhiteSpacesNotCountedAsChild.tsx, 14, 11)) + +; +>NoticeList : Symbol(NoticeList, Decl(jsxContainsOnlyTriviaWhiteSpacesNotCountedAsChild.tsx, 8, 1)) + + +>NoticeList : Symbol(NoticeList, Decl(jsxContainsOnlyTriviaWhiteSpacesNotCountedAsChild.tsx, 8, 1)) +>className : Symbol(className, Decl(jsxContainsOnlyTriviaWhiteSpacesNotCountedAsChild.tsx, 17, 11)) + +; +>NoticeList : Symbol(NoticeList, Decl(jsxContainsOnlyTriviaWhiteSpacesNotCountedAsChild.tsx, 8, 1)) + diff --git a/tests/baselines/reference/jsxContainsOnlyTriviaWhiteSpacesNotCountedAsChild.types b/tests/baselines/reference/jsxContainsOnlyTriviaWhiteSpacesNotCountedAsChild.types new file mode 100644 index 0000000000000..b39f5f10b4fda --- /dev/null +++ b/tests/baselines/reference/jsxContainsOnlyTriviaWhiteSpacesNotCountedAsChild.types @@ -0,0 +1,38 @@ +//// [tests/cases/compiler/jsxContainsOnlyTriviaWhiteSpacesNotCountedAsChild.tsx] //// + +=== jsxContainsOnlyTriviaWhiteSpacesNotCountedAsChild.tsx === +namespace JSX { + export interface ElementChildrenAttribute { + children: {}; +>children : {} + } +} + +interface Props { + className?: string | undefined; +>className : string | undefined +} + +function NoticeList(props: Props) { +>NoticeList : (props: Props) => null +>props : Props + + return null; +} + + +> : error +>NoticeList : (props: Props) => null +>className : string + +; +>NoticeList : (props: Props) => null + + +> : error +>NoticeList : (props: Props) => null +>className : string + +; +>NoticeList : (props: Props) => null + diff --git a/tests/baselines/reference/jsxEmptyExpressionNotCountedAsChild2.errors.txt b/tests/baselines/reference/jsxEmptyExpressionNotCountedAsChild2.errors.txt index 791fd8062fb1f..2060eafe1c35e 100644 --- a/tests/baselines/reference/jsxEmptyExpressionNotCountedAsChild2.errors.txt +++ b/tests/baselines/reference/jsxEmptyExpressionNotCountedAsChild2.errors.txt @@ -1,8 +1,5 @@ -jsxEmptyExpressionNotCountedAsChild2.tsx(28,2): error TS2322: Type '{ __children__: never[]; }' is not assignable to type '{ bar?: number | undefined; } & { __children__: () => number; }'. - Type '{ __children__: never[]; }' is not assignable to type '{ __children__: () => number; }'. - Types of property '__children__' are incompatible. - Type 'never[]' is not assignable to type '() => number'. - Type 'never[]' provides no match for the signature '(): number'. +jsxEmptyExpressionNotCountedAsChild2.tsx(28,2): error TS2322: Type '{}' is not assignable to type '{ bar?: number | undefined; } & { __children__: () => number; }'. + Property '__children__' is missing in type '{}' but required in type '{ __children__: () => number; }'. ==== jsxEmptyExpressionNotCountedAsChild2.tsx (1 errors) ==== @@ -35,9 +32,7 @@ jsxEmptyExpressionNotCountedAsChild2.tsx(28,2): error TS2322: Type '{ __children {}; // error ~~~~~~~~~~~~~ -!!! error TS2322: Type '{ __children__: never[]; }' is not assignable to type '{ bar?: number | undefined; } & { __children__: () => number; }'. -!!! error TS2322: Type '{ __children__: never[]; }' is not assignable to type '{ __children__: () => number; }'. -!!! error TS2322: Types of property '__children__' are incompatible. -!!! error TS2322: Type 'never[]' is not assignable to type '() => number'. -!!! error TS2322: Type 'never[]' provides no match for the signature '(): number'. +!!! error TS2322: Type '{}' is not assignable to type '{ bar?: number | undefined; } & { __children__: () => number; }'. +!!! error TS2322: Property '__children__' is missing in type '{}' but required in type '{ __children__: () => number; }'. +!!! related TS2728 jsxEmptyExpressionNotCountedAsChild2.tsx:22:46: '__children__' is declared here. \ No newline at end of file diff --git a/tests/cases/compiler/jsxContainsOnlyTriviaWhiteSpacesNotCountedAsChild.tsx b/tests/cases/compiler/jsxContainsOnlyTriviaWhiteSpacesNotCountedAsChild.tsx new file mode 100644 index 0000000000000..a2b73b7aeadf1 --- /dev/null +++ b/tests/cases/compiler/jsxContainsOnlyTriviaWhiteSpacesNotCountedAsChild.tsx @@ -0,0 +1,23 @@ +// @jsx: preserve +// @strict: true + +namespace JSX { + export interface ElementChildrenAttribute { + children: {}; + } +} + +interface Props { + className?: string | undefined; +} + +function NoticeList(props: Props) { + return null; +} + + +; + + + +; \ No newline at end of file