Skip to content

Commit a25321a

Browse files
authored
Ensure all JSX spread properties get visited in ES2018+ (#55859)
1 parent 85c2577 commit a25321a

10 files changed

+228
-2
lines changed

src/compiler/transformers/jsx.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import {
3636
isJsxSelfClosingElement,
3737
isJsxSpreadAttribute,
3838
isLineBreak,
39+
isObjectLiteralElementLike,
3940
isObjectLiteralExpression,
4041
isPropertyAssignment,
4142
isSourceFile,
@@ -63,6 +64,7 @@ import {
6364
ObjectLiteralElementLike,
6465
ObjectLiteralExpression,
6566
PropertyAssignment,
67+
sameMap,
6668
ScriptTarget,
6769
setIdentifierGeneratedImportReference,
6870
setParentRecursive,
@@ -444,7 +446,7 @@ export function transformJsx(context: TransformationContext): (x: SourceFile | B
444446

445447
function transformJsxSpreadAttributeToProps(node: JsxSpreadAttribute) {
446448
if (isObjectLiteralExpression(node.expression) && !hasProto(node.expression)) {
447-
return node.expression.properties;
449+
return sameMap(node.expression.properties, p => Debug.checkDefined(visitNode(p, visitor, isObjectLiteralElementLike)));
448450
}
449451
return factory.createSpreadAssignment(Debug.checkDefined(visitNode(node.expression, visitor, isExpression)));
450452
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/a.tsx(5,13): error TS2304: Cannot find name 'Comp'.
2+
/a.tsx(9,13): error TS2304: Cannot find name 'Comp'.
3+
/a.tsx(13,13): error TS2304: Cannot find name 'Comp'.
4+
/a.tsx(17,13): error TS2304: Cannot find name 'Comp'.
5+
6+
7+
==== /a.tsx (4 errors) ====
8+
declare const React: any;
9+
10+
const t1 = <div {...<span />} />;
11+
const t2 = <div {...<span className="foo" />} />;
12+
const t3 = <Comp
13+
~~~~
14+
!!! error TS2304: Cannot find name 'Comp'.
15+
right={<div>x</div>}
16+
{...{ wrong: <div>x</div>}}
17+
/>;
18+
const t4 = <Comp
19+
~~~~
20+
!!! error TS2304: Cannot find name 'Comp'.
21+
right={<div>x</div>}
22+
{...{ wrong() { return <div>x</div>; }}}
23+
/>;
24+
const t5 = <Comp
25+
~~~~
26+
!!! error TS2304: Cannot find name 'Comp'.
27+
right={<div>x</div>}
28+
{...{ get wrong() { return <div>x</div>; }}}
29+
/>;
30+
const t6 = <Comp
31+
~~~~
32+
!!! error TS2304: Cannot find name 'Comp'.
33+
right={<div>x</div>}
34+
{...{ set wrong(s) { let a = <div>x</div>; }}}
35+
/>;
36+
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
//// [tests/cases/compiler/jsxSpreadTag.ts] ////
2+
3+
//// [a.tsx]
4+
declare const React: any;
5+
6+
const t1 = <div {...<span />} />;
7+
const t2 = <div {...<span className="foo" />} />;
8+
const t3 = <Comp
9+
right={<div>x</div>}
10+
{...{ wrong: <div>x</div>}}
11+
/>;
12+
const t4 = <Comp
13+
right={<div>x</div>}
14+
{...{ wrong() { return <div>x</div>; }}}
15+
/>;
16+
const t5 = <Comp
17+
right={<div>x</div>}
18+
{...{ get wrong() { return <div>x</div>; }}}
19+
/>;
20+
const t6 = <Comp
21+
right={<div>x</div>}
22+
{...{ set wrong(s) { let a = <div>x</div>; }}}
23+
/>;
24+
25+
26+
//// [a.js]
27+
const t1 = React.createElement("div", { ...React.createElement("span", null) });
28+
const t2 = React.createElement("div", { ...React.createElement("span", { className: "foo" }) });
29+
const t3 = React.createElement(Comp, { right: React.createElement("div", null, "x"), wrong: React.createElement("div", null, "x") });
30+
const t4 = React.createElement(Comp, { right: React.createElement("div", null, "x"), wrong() { return React.createElement("div", null, "x"); } });
31+
const t5 = React.createElement(Comp, { right: React.createElement("div", null, "x"), get wrong() { return React.createElement("div", null, "x"); } });
32+
const t6 = React.createElement(Comp, { right: React.createElement("div", null, "x"), set wrong(s) { let a = React.createElement("div", null, "x"); } });
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
//// [tests/cases/compiler/jsxSpreadTag.ts] ////
2+
3+
=== /a.tsx ===
4+
declare const React: any;
5+
>React : Symbol(React, Decl(a.tsx, 0, 13))
6+
7+
const t1 = <div {...<span />} />;
8+
>t1 : Symbol(t1, Decl(a.tsx, 2, 5))
9+
10+
const t2 = <div {...<span className="foo" />} />;
11+
>t2 : Symbol(t2, Decl(a.tsx, 3, 5))
12+
>className : Symbol(className, Decl(a.tsx, 3, 25))
13+
14+
const t3 = <Comp
15+
>t3 : Symbol(t3, Decl(a.tsx, 4, 5))
16+
17+
right={<div>x</div>}
18+
>right : Symbol(right, Decl(a.tsx, 4, 16))
19+
20+
{...{ wrong: <div>x</div>}}
21+
>wrong : Symbol(wrong, Decl(a.tsx, 6, 9))
22+
23+
/>;
24+
const t4 = <Comp
25+
>t4 : Symbol(t4, Decl(a.tsx, 8, 5))
26+
27+
right={<div>x</div>}
28+
>right : Symbol(right, Decl(a.tsx, 8, 16))
29+
30+
{...{ wrong() { return <div>x</div>; }}}
31+
>wrong : Symbol(wrong, Decl(a.tsx, 10, 9))
32+
33+
/>;
34+
const t5 = <Comp
35+
>t5 : Symbol(t5, Decl(a.tsx, 12, 5))
36+
37+
right={<div>x</div>}
38+
>right : Symbol(right, Decl(a.tsx, 12, 16))
39+
40+
{...{ get wrong() { return <div>x</div>; }}}
41+
>wrong : Symbol(wrong, Decl(a.tsx, 14, 9))
42+
43+
/>;
44+
const t6 = <Comp
45+
>t6 : Symbol(t6, Decl(a.tsx, 16, 5))
46+
47+
right={<div>x</div>}
48+
>right : Symbol(right, Decl(a.tsx, 16, 16))
49+
50+
{...{ set wrong(s) { let a = <div>x</div>; }}}
51+
>wrong : Symbol(wrong, Decl(a.tsx, 18, 9))
52+
>s : Symbol(s, Decl(a.tsx, 18, 20))
53+
>a : Symbol(a, Decl(a.tsx, 18, 28))
54+
55+
/>;
56+
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
//// [tests/cases/compiler/jsxSpreadTag.ts] ////
2+
3+
=== /a.tsx ===
4+
declare const React: any;
5+
>React : any
6+
7+
const t1 = <div {...<span />} />;
8+
>t1 : any
9+
><div {...<span />} /> : any
10+
>div : any
11+
><span /> : any
12+
>span : any
13+
14+
const t2 = <div {...<span className="foo" />} />;
15+
>t2 : any
16+
><div {...<span className="foo" />} /> : any
17+
>div : any
18+
><span className="foo" /> : any
19+
>span : any
20+
>className : string
21+
22+
const t3 = <Comp
23+
>t3 : any
24+
><Comp right={<div>x</div>} {...{ wrong: <div>x</div>}}/> : any
25+
>Comp : any
26+
27+
right={<div>x</div>}
28+
>right : any
29+
><div>x</div> : any
30+
>div : any
31+
>div : any
32+
33+
{...{ wrong: <div>x</div>}}
34+
>{ wrong: <div>x</div>} : { wrong: any; }
35+
>wrong : any
36+
><div>x</div> : any
37+
>div : any
38+
>div : any
39+
40+
/>;
41+
const t4 = <Comp
42+
>t4 : any
43+
><Comp right={<div>x</div>} {...{ wrong() { return <div>x</div>; }}}/> : any
44+
>Comp : any
45+
46+
right={<div>x</div>}
47+
>right : any
48+
><div>x</div> : any
49+
>div : any
50+
>div : any
51+
52+
{...{ wrong() { return <div>x</div>; }}}
53+
>{ wrong() { return <div>x</div>; }} : { wrong(): any; }
54+
>wrong : () => any
55+
><div>x</div> : any
56+
>div : any
57+
>div : any
58+
59+
/>;
60+
const t5 = <Comp
61+
>t5 : any
62+
><Comp right={<div>x</div>} {...{ get wrong() { return <div>x</div>; }}}/> : any
63+
>Comp : any
64+
65+
right={<div>x</div>}
66+
>right : any
67+
><div>x</div> : any
68+
>div : any
69+
>div : any
70+
71+
{...{ get wrong() { return <div>x</div>; }}}
72+
>{ get wrong() { return <div>x</div>; }} : { readonly wrong: any; }
73+
>wrong : any
74+
><div>x</div> : any
75+
>div : any
76+
>div : any
77+
78+
/>;
79+
const t6 = <Comp
80+
>t6 : any
81+
><Comp right={<div>x</div>} {...{ set wrong(s) { let a = <div>x</div>; }}}/> : any
82+
>Comp : any
83+
84+
right={<div>x</div>}
85+
>right : any
86+
><div>x</div> : any
87+
>div : any
88+
>div : any
89+
90+
{...{ set wrong(s) { let a = <div>x</div>; }}}
91+
>{ set wrong(s) { let a = <div>x</div>; }} : { wrong: any; }
92+
>wrong : any
93+
>s : any
94+
>a : any
95+
><div>x</div> : any
96+
>div : any
97+
>div : any
98+
99+
/>;
100+

tests/cases/compiler/jsxSpreadTag.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// @jsx: react
2-
// @target: es2015
2+
// @target: es2015,esnext
33
// @filename: /a.tsx
44

55
declare const React: any;

0 commit comments

Comments
 (0)