Skip to content

Commit 27bbdf1

Browse files
jablkorbucktonorta
authored
Transform JSX spread children (#45693)
* Transform JSX spread children * Target es2015 to skip helper and refine emit Co-authored-by: Ron Buckton <[email protected]> Co-authored-by: Ron Buckton <[email protected]> Co-authored-by: Orta <[email protected]>
1 parent af689cc commit 27bbdf1

11 files changed

+335
-15
lines changed

src/compiler/transformers/jsx.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -547,7 +547,8 @@ namespace ts {
547547
}
548548

549549
function visitJsxExpression(node: JsxExpression) {
550-
return visitNode(node.expression, visitor, isExpression);
550+
const expression = visitNode(node.expression, visitor, isExpression);
551+
return node.dotDotDotToken ? factory.createSpreadElement(expression!) : expression;
551552
}
552553
}
553554

tests/baselines/reference/inlineJsxFactoryDeclarationsLocalTypes.js

+24-12
Original file line numberDiff line numberDiff line change
@@ -89,31 +89,36 @@ const _brokenTree2 = <DOMSFC x={1} y={2}>{tree}{tree}</DOMSFC>
8989

9090
//// [component.js]
9191
"use strict";
92+
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
93+
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
94+
if (ar || !(i in from)) {
95+
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
96+
ar[i] = from[i];
97+
}
98+
}
99+
return to.concat(ar || Array.prototype.slice.call(from));
100+
};
92101
var _this = this;
93102
exports.__esModule = true;
94103
exports.tree = exports.MyClass = exports.MySFC = void 0;
95104
/** @jsx predom */
96105
var renderer2_1 = require("./renderer2");
97-
var MySFC = function (props) { return (0, renderer2_1.predom)("p", null,
98-
props.x,
106+
var MySFC = function (props) { return renderer2_1.predom.apply(void 0, __spreadArray(["p", null, props.x,
99107
" + ",
100108
props.y,
101109
" = ",
102-
props.x + props.y,
103-
_this.props.children); };
110+
props.x + props.y], _this.props.children, false)); };
104111
exports.MySFC = MySFC;
105112
var MyClass = /** @class */ (function () {
106113
function MyClass(props) {
107114
this.props = props;
108115
}
109116
MyClass.prototype.render = function () {
110-
return (0, renderer2_1.predom)("p", null,
111-
this.props.x,
117+
return renderer2_1.predom.apply(void 0, __spreadArray(["p", null, this.props.x,
112118
" + ",
113119
this.props.y,
114120
" = ",
115-
this.props.x + this.props.y,
116-
this.props.children);
121+
this.props.x + this.props.y], this.props.children, false));
117122
};
118123
return MyClass;
119124
}());
@@ -124,6 +129,15 @@ exports.tree = (0, renderer2_1.predom)(exports.MySFC, { x: 1, y: 2 },
124129
exports["default"] = (0, renderer2_1.predom)("h", null);
125130
//// [index.js]
126131
"use strict";
132+
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
133+
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
134+
if (ar || !(i in from)) {
135+
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
136+
ar[i] = from[i];
137+
}
138+
}
139+
return to.concat(ar || Array.prototype.slice.call(from));
140+
};
127141
exports.__esModule = true;
128142
/** @jsx dom */
129143
var renderer_1 = require("./renderer");
@@ -142,13 +156,11 @@ var DOMClass = /** @class */ (function () {
142156
this.props = props;
143157
}
144158
DOMClass.prototype.render = function () {
145-
return (0, renderer_1.dom)("p", null,
146-
this.props.x,
159+
return renderer_1.dom.apply(void 0, __spreadArray(["p", null, this.props.x,
147160
" + ",
148161
this.props.y,
149162
" = ",
150-
this.props.x + this.props.y,
151-
this.props.children);
163+
this.props.x + this.props.y], this.props.children, false));
152164
};
153165
return DOMClass;
154166
}());
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
//// [tsxSpreadChildrenInvalidType.tsx]
2+
declare module JSX {
3+
interface Element { }
4+
interface IntrinsicElements {
5+
[s: string]: any;
6+
}
7+
}
8+
declare var React: any;
9+
10+
interface TodoProp {
11+
id: number;
12+
todo: string;
13+
}
14+
interface TodoListProps {
15+
todos: TodoProp[];
16+
}
17+
function Todo(prop: { key: number, todo: string }) {
18+
return <div>{prop.key.toString() + prop.todo}</div>;
19+
}
20+
function TodoList({ todos }: TodoListProps) {
21+
return <div>
22+
{...<Todo key={todos[0].id} todo={todos[0].todo} />}
23+
</div>;
24+
}
25+
function TodoListNoError({ todos }: TodoListProps) {
26+
// any is not checked
27+
return <div>
28+
{...(<Todo key={todos[0].id} todo={todos[0].todo} /> as any)}
29+
</div>;
30+
}
31+
let x: TodoListProps;
32+
<TodoList {...x}/>
33+
34+
35+
//// [tsxSpreadChildrenInvalidType.js]
36+
function Todo(prop) {
37+
return React.createElement("div", null, prop.key.toString() + prop.todo);
38+
}
39+
function TodoList({ todos }) {
40+
return React.createElement("div", null, ...React.createElement(Todo, { key: todos[0].id, todo: todos[0].todo }));
41+
}
42+
function TodoListNoError({ todos }) {
43+
// any is not checked
44+
return React.createElement("div", null, ...React.createElement(Todo, { key: todos[0].id, todo: todos[0].todo }));
45+
}
46+
let x;
47+
React.createElement(TodoList, Object.assign({}, x));
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
tests/cases/conformance/jsx/tsxSpreadChildrenInvalidType.tsx(21,9): error TS2609: JSX spread child must be an array type.
2+
3+
4+
==== tests/cases/conformance/jsx/tsxSpreadChildrenInvalidType.tsx (1 errors) ====
5+
declare module JSX {
6+
interface Element { }
7+
interface IntrinsicElements {
8+
[s: string]: any;
9+
}
10+
}
11+
declare var React: any;
12+
13+
interface TodoProp {
14+
id: number;
15+
todo: string;
16+
}
17+
interface TodoListProps {
18+
todos: TodoProp[];
19+
}
20+
function Todo(prop: { key: number, todo: string }) {
21+
return <div>{prop.key.toString() + prop.todo}</div>;
22+
}
23+
function TodoList({ todos }: TodoListProps) {
24+
return <div>
25+
{...<Todo key={todos[0].id} todo={todos[0].todo} />}
26+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
27+
!!! error TS2609: JSX spread child must be an array type.
28+
</div>;
29+
}
30+
function TodoListNoError({ todos }: TodoListProps) {
31+
// any is not checked
32+
return <div>
33+
{...(<Todo key={todos[0].id} todo={todos[0].todo} /> as any)}
34+
</div>;
35+
}
36+
let x: TodoListProps;
37+
<TodoList {...x}/>
38+

tests/baselines/reference/tsxSpreadChildrenInvalidType.js renamed to tests/baselines/reference/tsxSpreadChildrenInvalidType(target=es5).js

+11-2
Original file line numberDiff line numberDiff line change
@@ -44,17 +44,26 @@ var __assign = (this && this.__assign) || function () {
4444
};
4545
return __assign.apply(this, arguments);
4646
};
47+
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
48+
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
49+
if (ar || !(i in from)) {
50+
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
51+
ar[i] = from[i];
52+
}
53+
}
54+
return to.concat(ar || Array.prototype.slice.call(from));
55+
};
4756
function Todo(prop) {
4857
return React.createElement("div", null, prop.key.toString() + prop.todo);
4958
}
5059
function TodoList(_a) {
5160
var todos = _a.todos;
52-
return React.createElement("div", null, React.createElement(Todo, { key: todos[0].id, todo: todos[0].todo }));
61+
return React.createElement.apply(React, __spreadArray(["div", null], React.createElement(Todo, { key: todos[0].id, todo: todos[0].todo }), false));
5362
}
5463
function TodoListNoError(_a) {
5564
var todos = _a.todos;
5665
// any is not checked
57-
return React.createElement("div", null, React.createElement(Todo, { key: todos[0].id, todo: todos[0].todo }));
66+
return React.createElement.apply(React, __spreadArray(["div", null], React.createElement(Todo, { key: todos[0].id, todo: todos[0].todo }), false));
5867
}
5968
var x;
6069
React.createElement(TodoList, __assign({}, x));
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
=== tests/cases/conformance/jsx/tsxSpreadChildrenInvalidType.tsx ===
2+
declare module JSX {
3+
>JSX : Symbol(JSX, Decl(tsxSpreadChildrenInvalidType.tsx, 0, 0))
4+
5+
interface Element { }
6+
>Element : Symbol(Element, Decl(tsxSpreadChildrenInvalidType.tsx, 0, 20))
7+
8+
interface IntrinsicElements {
9+
>IntrinsicElements : Symbol(IntrinsicElements, Decl(tsxSpreadChildrenInvalidType.tsx, 1, 22))
10+
11+
[s: string]: any;
12+
>s : Symbol(s, Decl(tsxSpreadChildrenInvalidType.tsx, 3, 3))
13+
}
14+
}
15+
declare var React: any;
16+
>React : Symbol(React, Decl(tsxSpreadChildrenInvalidType.tsx, 6, 11))
17+
18+
interface TodoProp {
19+
>TodoProp : Symbol(TodoProp, Decl(tsxSpreadChildrenInvalidType.tsx, 6, 23))
20+
21+
id: number;
22+
>id : Symbol(TodoProp.id, Decl(tsxSpreadChildrenInvalidType.tsx, 8, 20))
23+
24+
todo: string;
25+
>todo : Symbol(TodoProp.todo, Decl(tsxSpreadChildrenInvalidType.tsx, 9, 15))
26+
}
27+
interface TodoListProps {
28+
>TodoListProps : Symbol(TodoListProps, Decl(tsxSpreadChildrenInvalidType.tsx, 11, 1))
29+
30+
todos: TodoProp[];
31+
>todos : Symbol(TodoListProps.todos, Decl(tsxSpreadChildrenInvalidType.tsx, 12, 25))
32+
>TodoProp : Symbol(TodoProp, Decl(tsxSpreadChildrenInvalidType.tsx, 6, 23))
33+
}
34+
function Todo(prop: { key: number, todo: string }) {
35+
>Todo : Symbol(Todo, Decl(tsxSpreadChildrenInvalidType.tsx, 14, 1))
36+
>prop : Symbol(prop, Decl(tsxSpreadChildrenInvalidType.tsx, 15, 14))
37+
>key : Symbol(key, Decl(tsxSpreadChildrenInvalidType.tsx, 15, 21))
38+
>todo : Symbol(todo, Decl(tsxSpreadChildrenInvalidType.tsx, 15, 34))
39+
40+
return <div>{prop.key.toString() + prop.todo}</div>;
41+
>div : Symbol(JSX.IntrinsicElements, Decl(tsxSpreadChildrenInvalidType.tsx, 1, 22))
42+
>prop.key.toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --))
43+
>prop.key : Symbol(key, Decl(tsxSpreadChildrenInvalidType.tsx, 15, 21))
44+
>prop : Symbol(prop, Decl(tsxSpreadChildrenInvalidType.tsx, 15, 14))
45+
>key : Symbol(key, Decl(tsxSpreadChildrenInvalidType.tsx, 15, 21))
46+
>toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --))
47+
>prop.todo : Symbol(todo, Decl(tsxSpreadChildrenInvalidType.tsx, 15, 34))
48+
>prop : Symbol(prop, Decl(tsxSpreadChildrenInvalidType.tsx, 15, 14))
49+
>todo : Symbol(todo, Decl(tsxSpreadChildrenInvalidType.tsx, 15, 34))
50+
>div : Symbol(JSX.IntrinsicElements, Decl(tsxSpreadChildrenInvalidType.tsx, 1, 22))
51+
}
52+
function TodoList({ todos }: TodoListProps) {
53+
>TodoList : Symbol(TodoList, Decl(tsxSpreadChildrenInvalidType.tsx, 17, 1))
54+
>todos : Symbol(todos, Decl(tsxSpreadChildrenInvalidType.tsx, 18, 19))
55+
>TodoListProps : Symbol(TodoListProps, Decl(tsxSpreadChildrenInvalidType.tsx, 11, 1))
56+
57+
return <div>
58+
>div : Symbol(JSX.IntrinsicElements, Decl(tsxSpreadChildrenInvalidType.tsx, 1, 22))
59+
60+
{...<Todo key={todos[0].id} todo={todos[0].todo} />}
61+
>Todo : Symbol(Todo, Decl(tsxSpreadChildrenInvalidType.tsx, 14, 1))
62+
>key : Symbol(key, Decl(tsxSpreadChildrenInvalidType.tsx, 20, 17))
63+
>todos[0].id : Symbol(TodoProp.id, Decl(tsxSpreadChildrenInvalidType.tsx, 8, 20))
64+
>todos : Symbol(todos, Decl(tsxSpreadChildrenInvalidType.tsx, 18, 19))
65+
>id : Symbol(TodoProp.id, Decl(tsxSpreadChildrenInvalidType.tsx, 8, 20))
66+
>todo : Symbol(todo, Decl(tsxSpreadChildrenInvalidType.tsx, 20, 35))
67+
>todos[0].todo : Symbol(TodoProp.todo, Decl(tsxSpreadChildrenInvalidType.tsx, 9, 15))
68+
>todos : Symbol(todos, Decl(tsxSpreadChildrenInvalidType.tsx, 18, 19))
69+
>todo : Symbol(TodoProp.todo, Decl(tsxSpreadChildrenInvalidType.tsx, 9, 15))
70+
71+
</div>;
72+
>div : Symbol(JSX.IntrinsicElements, Decl(tsxSpreadChildrenInvalidType.tsx, 1, 22))
73+
}
74+
function TodoListNoError({ todos }: TodoListProps) {
75+
>TodoListNoError : Symbol(TodoListNoError, Decl(tsxSpreadChildrenInvalidType.tsx, 22, 1))
76+
>todos : Symbol(todos, Decl(tsxSpreadChildrenInvalidType.tsx, 23, 26))
77+
>TodoListProps : Symbol(TodoListProps, Decl(tsxSpreadChildrenInvalidType.tsx, 11, 1))
78+
79+
// any is not checked
80+
return <div>
81+
>div : Symbol(JSX.IntrinsicElements, Decl(tsxSpreadChildrenInvalidType.tsx, 1, 22))
82+
83+
{...(<Todo key={todos[0].id} todo={todos[0].todo} /> as any)}
84+
>Todo : Symbol(Todo, Decl(tsxSpreadChildrenInvalidType.tsx, 14, 1))
85+
>key : Symbol(key, Decl(tsxSpreadChildrenInvalidType.tsx, 26, 18))
86+
>todos[0].id : Symbol(TodoProp.id, Decl(tsxSpreadChildrenInvalidType.tsx, 8, 20))
87+
>todos : Symbol(todos, Decl(tsxSpreadChildrenInvalidType.tsx, 23, 26))
88+
>id : Symbol(TodoProp.id, Decl(tsxSpreadChildrenInvalidType.tsx, 8, 20))
89+
>todo : Symbol(todo, Decl(tsxSpreadChildrenInvalidType.tsx, 26, 36))
90+
>todos[0].todo : Symbol(TodoProp.todo, Decl(tsxSpreadChildrenInvalidType.tsx, 9, 15))
91+
>todos : Symbol(todos, Decl(tsxSpreadChildrenInvalidType.tsx, 23, 26))
92+
>todo : Symbol(TodoProp.todo, Decl(tsxSpreadChildrenInvalidType.tsx, 9, 15))
93+
94+
</div>;
95+
>div : Symbol(JSX.IntrinsicElements, Decl(tsxSpreadChildrenInvalidType.tsx, 1, 22))
96+
}
97+
let x: TodoListProps;
98+
>x : Symbol(x, Decl(tsxSpreadChildrenInvalidType.tsx, 29, 3))
99+
>TodoListProps : Symbol(TodoListProps, Decl(tsxSpreadChildrenInvalidType.tsx, 11, 1))
100+
101+
<TodoList {...x}/>
102+
>TodoList : Symbol(TodoList, Decl(tsxSpreadChildrenInvalidType.tsx, 17, 1))
103+
>x : Symbol(x, Decl(tsxSpreadChildrenInvalidType.tsx, 29, 3))
104+

0 commit comments

Comments
 (0)