Skip to content

Commit f1ac8cd

Browse files
authored
Fix children prop for react-jsx and react-jsxdev (#40630)
* Fix children prop for `react-jsx` and `react-jsxdev` * Add tests
1 parent 6c6ddfe commit f1ac8cd

8 files changed

+88
-13
lines changed

src/compiler/transformers/jsx.ts

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -208,33 +208,36 @@ namespace ts {
208208
let objectProperties: Expression;
209209
const keyAttr = find(node.attributes.properties, p => !!p.name && isIdentifier(p.name) && p.name.escapedText === "key") as JsxAttribute | undefined;
210210
const attrs = keyAttr ? filter(node.attributes.properties, p => p !== keyAttr) : node.attributes.properties;
211-
if (attrs.length === 0) {
212-
objectProperties = factory.createObjectLiteralExpression([]);
213-
// When there are no attributes, React wants {}
214-
}
215-
else {
211+
212+
let segments: Expression[] = [];
213+
if (attrs.length) {
216214
// Map spans of JsxAttribute nodes into object literals and spans
217215
// of JsxSpreadAttribute nodes into expressions.
218-
const segments = flatten<Expression | ObjectLiteralExpression>(
216+
segments = flatten(
219217
spanMap(attrs, isJsxSpreadAttribute, (attrs, isSpread) => isSpread
220218
? map(attrs, transformJsxSpreadAttributeToExpression)
221219
: factory.createObjectLiteralExpression(map(attrs, transformJsxAttributeToObjectLiteralElement))
222220
)
223221
);
224222

225-
if (children && children.length) {
226-
const result = convertJsxChildrenToChildrenPropObject(children);
227-
if (result) {
228-
segments.push(result);
229-
}
230-
}
231-
232223
if (isJsxSpreadAttribute(attrs[0])) {
233224
// We must always emit at least one object literal before a spread
234225
// argument.factory.createObjectLiteral
235226
segments.unshift(factory.createObjectLiteralExpression());
236227
}
228+
}
229+
if (children && children.length) {
230+
const result = convertJsxChildrenToChildrenPropObject(children);
231+
if (result) {
232+
segments.push(result);
233+
}
234+
}
237235

236+
if (segments.length === 0) {
237+
objectProperties = factory.createObjectLiteralExpression([]);
238+
// When there are no attributes, React wants {}
239+
}
240+
else {
238241
// Either emit one big object literal (no spread attribs), or
239242
// a call to the __assign helper.
240243
objectProperties = singleOrUndefined(segments) || emitHelpers().createAssignHelper(segments);
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
//// [jsxJsxsCjsTransformChildren.tsx]
2+
/// <reference path="/.lib/react16.d.ts" />
3+
const a = <div>text</div>;
4+
5+
export {};
6+
7+
8+
//// [jsxJsxsCjsTransformChildren.js]
9+
"use strict";
10+
exports.__esModule = true;
11+
var jsx_runtime_1 = require("react/jsx-runtime");
12+
/// <reference path="react16.d.ts" />
13+
var a = jsx_runtime_1.jsx("div", { children: "text" }, void 0);
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
=== tests/cases/conformance/jsx/jsxs/jsxJsxsCjsTransformChildren.tsx ===
2+
/// <reference path="react16.d.ts" />
3+
const a = <div>text</div>;
4+
>a : Symbol(a, Decl(jsxJsxsCjsTransformChildren.tsx, 1, 5))
5+
>div : Symbol(JSX.IntrinsicElements.div, Decl(react16.d.ts, 2420, 114))
6+
>div : Symbol(JSX.IntrinsicElements.div, Decl(react16.d.ts, 2420, 114))
7+
8+
export {};
9+
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
=== tests/cases/conformance/jsx/jsxs/jsxJsxsCjsTransformChildren.tsx ===
2+
/// <reference path="react16.d.ts" />
3+
const a = <div>text</div>;
4+
>a : JSX.Element
5+
><div>text</div> : JSX.Element
6+
>div : any
7+
>div : any
8+
9+
export {};
10+
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
//// [jsxJsxsCjsTransformChildren.tsx]
2+
/// <reference path="/.lib/react16.d.ts" />
3+
const a = <div>text</div>;
4+
5+
export {};
6+
7+
8+
//// [jsxJsxsCjsTransformChildren.js]
9+
"use strict";
10+
exports.__esModule = true;
11+
var jsx_dev_runtime_1 = require("react/jsx-dev-runtime");
12+
var _jsxFileName = "tests/cases/conformance/jsx/jsxs/jsxJsxsCjsTransformChildren.tsx";
13+
/// <reference path="react16.d.ts" />
14+
var a = jsx_dev_runtime_1.jsxDEV("div", { children: "text" }, void 0, false, { fileName: _jsxFileName, lineNumber: 2, columnNumber: 10 }, this);
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
=== tests/cases/conformance/jsx/jsxs/jsxJsxsCjsTransformChildren.tsx ===
2+
/// <reference path="react16.d.ts" />
3+
const a = <div>text</div>;
4+
>a : Symbol(a, Decl(jsxJsxsCjsTransformChildren.tsx, 1, 5))
5+
>div : Symbol(JSX.IntrinsicElements.div, Decl(react16.d.ts, 2420, 114))
6+
>div : Symbol(JSX.IntrinsicElements.div, Decl(react16.d.ts, 2420, 114))
7+
8+
export {};
9+
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
=== tests/cases/conformance/jsx/jsxs/jsxJsxsCjsTransformChildren.tsx ===
2+
/// <reference path="react16.d.ts" />
3+
const a = <div>text</div>;
4+
>a : JSX.Element
5+
><div>text</div> : JSX.Element
6+
>div : any
7+
>div : any
8+
9+
export {};
10+
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// @jsx: react-jsx,react-jsxdev
2+
// @strict: true
3+
// @module: commonjs
4+
/// <reference path="/.lib/react16.d.ts" />
5+
const a = <div>text</div>;
6+
7+
export {};

0 commit comments

Comments
 (0)