diff --git a/src/compiler/transformers/jsx.ts b/src/compiler/transformers/jsx.ts index 018e2ad2cb411..e274f3275f144 100644 --- a/src/compiler/transformers/jsx.ts +++ b/src/compiler/transformers/jsx.ts @@ -547,7 +547,8 @@ namespace ts { } function visitJsxExpression(node: JsxExpression) { - return visitNode(node.expression, visitor, isExpression); + const expression = visitNode(node.expression, visitor, isExpression); + return node.dotDotDotToken ? factory.createSpreadElement(expression!) : expression; } } diff --git a/tests/baselines/reference/inlineJsxFactoryDeclarationsLocalTypes.js b/tests/baselines/reference/inlineJsxFactoryDeclarationsLocalTypes.js index 177f997297b44..fbf032054279d 100644 --- a/tests/baselines/reference/inlineJsxFactoryDeclarationsLocalTypes.js +++ b/tests/baselines/reference/inlineJsxFactoryDeclarationsLocalTypes.js @@ -89,31 +89,36 @@ const _brokenTree2 = {tree}{tree} //// [component.js] "use strict"; +var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { + if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { + if (ar || !(i in from)) { + if (!ar) ar = Array.prototype.slice.call(from, 0, i); + ar[i] = from[i]; + } + } + return to.concat(ar || Array.prototype.slice.call(from)); +}; var _this = this; exports.__esModule = true; exports.tree = exports.MyClass = exports.MySFC = void 0; /** @jsx predom */ var renderer2_1 = require("./renderer2"); -var MySFC = function (props) { return (0, renderer2_1.predom)("p", null, - props.x, +var MySFC = function (props) { return renderer2_1.predom.apply(void 0, __spreadArray(["p", null, props.x, " + ", props.y, " = ", - props.x + props.y, - _this.props.children); }; + props.x + props.y], _this.props.children, false)); }; exports.MySFC = MySFC; var MyClass = /** @class */ (function () { function MyClass(props) { this.props = props; } MyClass.prototype.render = function () { - return (0, renderer2_1.predom)("p", null, - this.props.x, + return renderer2_1.predom.apply(void 0, __spreadArray(["p", null, this.props.x, " + ", this.props.y, " = ", - this.props.x + this.props.y, - this.props.children); + this.props.x + this.props.y], this.props.children, false)); }; return MyClass; }()); @@ -124,6 +129,15 @@ exports.tree = (0, renderer2_1.predom)(exports.MySFC, { x: 1, y: 2 }, exports["default"] = (0, renderer2_1.predom)("h", null); //// [index.js] "use strict"; +var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { + if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { + if (ar || !(i in from)) { + if (!ar) ar = Array.prototype.slice.call(from, 0, i); + ar[i] = from[i]; + } + } + return to.concat(ar || Array.prototype.slice.call(from)); +}; exports.__esModule = true; /** @jsx dom */ var renderer_1 = require("./renderer"); @@ -142,13 +156,11 @@ var DOMClass = /** @class */ (function () { this.props = props; } DOMClass.prototype.render = function () { - return (0, renderer_1.dom)("p", null, - this.props.x, + return renderer_1.dom.apply(void 0, __spreadArray(["p", null, this.props.x, " + ", this.props.y, " = ", - this.props.x + this.props.y, - this.props.children); + this.props.x + this.props.y], this.props.children, false)); }; return DOMClass; }()); diff --git a/tests/baselines/reference/tsxSpreadChildrenInvalidType.errors.txt b/tests/baselines/reference/tsxSpreadChildrenInvalidType(target=es2015).errors.txt similarity index 100% rename from tests/baselines/reference/tsxSpreadChildrenInvalidType.errors.txt rename to tests/baselines/reference/tsxSpreadChildrenInvalidType(target=es2015).errors.txt diff --git a/tests/baselines/reference/tsxSpreadChildrenInvalidType(target=es2015).js b/tests/baselines/reference/tsxSpreadChildrenInvalidType(target=es2015).js new file mode 100644 index 0000000000000..a4d7219b0a617 --- /dev/null +++ b/tests/baselines/reference/tsxSpreadChildrenInvalidType(target=es2015).js @@ -0,0 +1,47 @@ +//// [tsxSpreadChildrenInvalidType.tsx] +declare module JSX { + interface Element { } + interface IntrinsicElements { + [s: string]: any; + } +} +declare var React: any; + +interface TodoProp { + id: number; + todo: string; +} +interface TodoListProps { + todos: TodoProp[]; +} +function Todo(prop: { key: number, todo: string }) { + return
{prop.key.toString() + prop.todo}
; +} +function TodoList({ todos }: TodoListProps) { + return
+ {...} +
; +} +function TodoListNoError({ todos }: TodoListProps) { + // any is not checked + return
+ {...( as any)} +
; +} +let x: TodoListProps; + + + +//// [tsxSpreadChildrenInvalidType.js] +function Todo(prop) { + return React.createElement("div", null, prop.key.toString() + prop.todo); +} +function TodoList({ todos }) { + return React.createElement("div", null, ...React.createElement(Todo, { key: todos[0].id, todo: todos[0].todo })); +} +function TodoListNoError({ todos }) { + // any is not checked + return React.createElement("div", null, ...React.createElement(Todo, { key: todos[0].id, todo: todos[0].todo })); +} +let x; +React.createElement(TodoList, Object.assign({}, x)); diff --git a/tests/baselines/reference/tsxSpreadChildrenInvalidType.symbols b/tests/baselines/reference/tsxSpreadChildrenInvalidType(target=es2015).symbols similarity index 100% rename from tests/baselines/reference/tsxSpreadChildrenInvalidType.symbols rename to tests/baselines/reference/tsxSpreadChildrenInvalidType(target=es2015).symbols diff --git a/tests/baselines/reference/tsxSpreadChildrenInvalidType.types b/tests/baselines/reference/tsxSpreadChildrenInvalidType(target=es2015).types similarity index 100% rename from tests/baselines/reference/tsxSpreadChildrenInvalidType.types rename to tests/baselines/reference/tsxSpreadChildrenInvalidType(target=es2015).types diff --git a/tests/baselines/reference/tsxSpreadChildrenInvalidType(target=es5).errors.txt b/tests/baselines/reference/tsxSpreadChildrenInvalidType(target=es5).errors.txt new file mode 100644 index 0000000000000..d1524c6bf3a97 --- /dev/null +++ b/tests/baselines/reference/tsxSpreadChildrenInvalidType(target=es5).errors.txt @@ -0,0 +1,38 @@ +tests/cases/conformance/jsx/tsxSpreadChildrenInvalidType.tsx(21,9): error TS2609: JSX spread child must be an array type. + + +==== tests/cases/conformance/jsx/tsxSpreadChildrenInvalidType.tsx (1 errors) ==== + declare module JSX { + interface Element { } + interface IntrinsicElements { + [s: string]: any; + } + } + declare var React: any; + + interface TodoProp { + id: number; + todo: string; + } + interface TodoListProps { + todos: TodoProp[]; + } + function Todo(prop: { key: number, todo: string }) { + return
{prop.key.toString() + prop.todo}
; + } + function TodoList({ todos }: TodoListProps) { + return
+ {...} + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2609: JSX spread child must be an array type. +
; + } + function TodoListNoError({ todos }: TodoListProps) { + // any is not checked + return
+ {...( as any)} +
; + } + let x: TodoListProps; + + \ No newline at end of file diff --git a/tests/baselines/reference/tsxSpreadChildrenInvalidType.js b/tests/baselines/reference/tsxSpreadChildrenInvalidType(target=es5).js similarity index 66% rename from tests/baselines/reference/tsxSpreadChildrenInvalidType.js rename to tests/baselines/reference/tsxSpreadChildrenInvalidType(target=es5).js index d8c0025696994..bdf486f44d189 100644 --- a/tests/baselines/reference/tsxSpreadChildrenInvalidType.js +++ b/tests/baselines/reference/tsxSpreadChildrenInvalidType(target=es5).js @@ -44,17 +44,26 @@ var __assign = (this && this.__assign) || function () { }; return __assign.apply(this, arguments); }; +var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { + if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { + if (ar || !(i in from)) { + if (!ar) ar = Array.prototype.slice.call(from, 0, i); + ar[i] = from[i]; + } + } + return to.concat(ar || Array.prototype.slice.call(from)); +}; function Todo(prop) { return React.createElement("div", null, prop.key.toString() + prop.todo); } function TodoList(_a) { var todos = _a.todos; - return React.createElement("div", null, React.createElement(Todo, { key: todos[0].id, todo: todos[0].todo })); + return React.createElement.apply(React, __spreadArray(["div", null], React.createElement(Todo, { key: todos[0].id, todo: todos[0].todo }), false)); } function TodoListNoError(_a) { var todos = _a.todos; // any is not checked - return React.createElement("div", null, React.createElement(Todo, { key: todos[0].id, todo: todos[0].todo })); + return React.createElement.apply(React, __spreadArray(["div", null], React.createElement(Todo, { key: todos[0].id, todo: todos[0].todo }), false)); } var x; React.createElement(TodoList, __assign({}, x)); diff --git a/tests/baselines/reference/tsxSpreadChildrenInvalidType(target=es5).symbols b/tests/baselines/reference/tsxSpreadChildrenInvalidType(target=es5).symbols new file mode 100644 index 0000000000000..5e41936f306e1 --- /dev/null +++ b/tests/baselines/reference/tsxSpreadChildrenInvalidType(target=es5).symbols @@ -0,0 +1,104 @@ +=== tests/cases/conformance/jsx/tsxSpreadChildrenInvalidType.tsx === +declare module JSX { +>JSX : Symbol(JSX, Decl(tsxSpreadChildrenInvalidType.tsx, 0, 0)) + + interface Element { } +>Element : Symbol(Element, Decl(tsxSpreadChildrenInvalidType.tsx, 0, 20)) + + interface IntrinsicElements { +>IntrinsicElements : Symbol(IntrinsicElements, Decl(tsxSpreadChildrenInvalidType.tsx, 1, 22)) + + [s: string]: any; +>s : Symbol(s, Decl(tsxSpreadChildrenInvalidType.tsx, 3, 3)) + } +} +declare var React: any; +>React : Symbol(React, Decl(tsxSpreadChildrenInvalidType.tsx, 6, 11)) + +interface TodoProp { +>TodoProp : Symbol(TodoProp, Decl(tsxSpreadChildrenInvalidType.tsx, 6, 23)) + + id: number; +>id : Symbol(TodoProp.id, Decl(tsxSpreadChildrenInvalidType.tsx, 8, 20)) + + todo: string; +>todo : Symbol(TodoProp.todo, Decl(tsxSpreadChildrenInvalidType.tsx, 9, 15)) +} +interface TodoListProps { +>TodoListProps : Symbol(TodoListProps, Decl(tsxSpreadChildrenInvalidType.tsx, 11, 1)) + + todos: TodoProp[]; +>todos : Symbol(TodoListProps.todos, Decl(tsxSpreadChildrenInvalidType.tsx, 12, 25)) +>TodoProp : Symbol(TodoProp, Decl(tsxSpreadChildrenInvalidType.tsx, 6, 23)) +} +function Todo(prop: { key: number, todo: string }) { +>Todo : Symbol(Todo, Decl(tsxSpreadChildrenInvalidType.tsx, 14, 1)) +>prop : Symbol(prop, Decl(tsxSpreadChildrenInvalidType.tsx, 15, 14)) +>key : Symbol(key, Decl(tsxSpreadChildrenInvalidType.tsx, 15, 21)) +>todo : Symbol(todo, Decl(tsxSpreadChildrenInvalidType.tsx, 15, 34)) + + return
{prop.key.toString() + prop.todo}
; +>div : Symbol(JSX.IntrinsicElements, Decl(tsxSpreadChildrenInvalidType.tsx, 1, 22)) +>prop.key.toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) +>prop.key : Symbol(key, Decl(tsxSpreadChildrenInvalidType.tsx, 15, 21)) +>prop : Symbol(prop, Decl(tsxSpreadChildrenInvalidType.tsx, 15, 14)) +>key : Symbol(key, Decl(tsxSpreadChildrenInvalidType.tsx, 15, 21)) +>toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) +>prop.todo : Symbol(todo, Decl(tsxSpreadChildrenInvalidType.tsx, 15, 34)) +>prop : Symbol(prop, Decl(tsxSpreadChildrenInvalidType.tsx, 15, 14)) +>todo : Symbol(todo, Decl(tsxSpreadChildrenInvalidType.tsx, 15, 34)) +>div : Symbol(JSX.IntrinsicElements, Decl(tsxSpreadChildrenInvalidType.tsx, 1, 22)) +} +function TodoList({ todos }: TodoListProps) { +>TodoList : Symbol(TodoList, Decl(tsxSpreadChildrenInvalidType.tsx, 17, 1)) +>todos : Symbol(todos, Decl(tsxSpreadChildrenInvalidType.tsx, 18, 19)) +>TodoListProps : Symbol(TodoListProps, Decl(tsxSpreadChildrenInvalidType.tsx, 11, 1)) + + return
+>div : Symbol(JSX.IntrinsicElements, Decl(tsxSpreadChildrenInvalidType.tsx, 1, 22)) + + {...} +>Todo : Symbol(Todo, Decl(tsxSpreadChildrenInvalidType.tsx, 14, 1)) +>key : Symbol(key, Decl(tsxSpreadChildrenInvalidType.tsx, 20, 17)) +>todos[0].id : Symbol(TodoProp.id, Decl(tsxSpreadChildrenInvalidType.tsx, 8, 20)) +>todos : Symbol(todos, Decl(tsxSpreadChildrenInvalidType.tsx, 18, 19)) +>id : Symbol(TodoProp.id, Decl(tsxSpreadChildrenInvalidType.tsx, 8, 20)) +>todo : Symbol(todo, Decl(tsxSpreadChildrenInvalidType.tsx, 20, 35)) +>todos[0].todo : Symbol(TodoProp.todo, Decl(tsxSpreadChildrenInvalidType.tsx, 9, 15)) +>todos : Symbol(todos, Decl(tsxSpreadChildrenInvalidType.tsx, 18, 19)) +>todo : Symbol(TodoProp.todo, Decl(tsxSpreadChildrenInvalidType.tsx, 9, 15)) + +
; +>div : Symbol(JSX.IntrinsicElements, Decl(tsxSpreadChildrenInvalidType.tsx, 1, 22)) +} +function TodoListNoError({ todos }: TodoListProps) { +>TodoListNoError : Symbol(TodoListNoError, Decl(tsxSpreadChildrenInvalidType.tsx, 22, 1)) +>todos : Symbol(todos, Decl(tsxSpreadChildrenInvalidType.tsx, 23, 26)) +>TodoListProps : Symbol(TodoListProps, Decl(tsxSpreadChildrenInvalidType.tsx, 11, 1)) + + // any is not checked + return
+>div : Symbol(JSX.IntrinsicElements, Decl(tsxSpreadChildrenInvalidType.tsx, 1, 22)) + + {...( as any)} +>Todo : Symbol(Todo, Decl(tsxSpreadChildrenInvalidType.tsx, 14, 1)) +>key : Symbol(key, Decl(tsxSpreadChildrenInvalidType.tsx, 26, 18)) +>todos[0].id : Symbol(TodoProp.id, Decl(tsxSpreadChildrenInvalidType.tsx, 8, 20)) +>todos : Symbol(todos, Decl(tsxSpreadChildrenInvalidType.tsx, 23, 26)) +>id : Symbol(TodoProp.id, Decl(tsxSpreadChildrenInvalidType.tsx, 8, 20)) +>todo : Symbol(todo, Decl(tsxSpreadChildrenInvalidType.tsx, 26, 36)) +>todos[0].todo : Symbol(TodoProp.todo, Decl(tsxSpreadChildrenInvalidType.tsx, 9, 15)) +>todos : Symbol(todos, Decl(tsxSpreadChildrenInvalidType.tsx, 23, 26)) +>todo : Symbol(TodoProp.todo, Decl(tsxSpreadChildrenInvalidType.tsx, 9, 15)) + +
; +>div : Symbol(JSX.IntrinsicElements, Decl(tsxSpreadChildrenInvalidType.tsx, 1, 22)) +} +let x: TodoListProps; +>x : Symbol(x, Decl(tsxSpreadChildrenInvalidType.tsx, 29, 3)) +>TodoListProps : Symbol(TodoListProps, Decl(tsxSpreadChildrenInvalidType.tsx, 11, 1)) + + +>TodoList : Symbol(TodoList, Decl(tsxSpreadChildrenInvalidType.tsx, 17, 1)) +>x : Symbol(x, Decl(tsxSpreadChildrenInvalidType.tsx, 29, 3)) + diff --git a/tests/baselines/reference/tsxSpreadChildrenInvalidType(target=es5).types b/tests/baselines/reference/tsxSpreadChildrenInvalidType(target=es5).types new file mode 100644 index 0000000000000..b8eb048703703 --- /dev/null +++ b/tests/baselines/reference/tsxSpreadChildrenInvalidType(target=es5).types @@ -0,0 +1,108 @@ +=== tests/cases/conformance/jsx/tsxSpreadChildrenInvalidType.tsx === +declare module JSX { + interface Element { } + interface IntrinsicElements { + [s: string]: any; +>s : string + } +} +declare var React: any; +>React : any + +interface TodoProp { + id: number; +>id : number + + todo: string; +>todo : string +} +interface TodoListProps { + todos: TodoProp[]; +>todos : TodoProp[] +} +function Todo(prop: { key: number, todo: string }) { +>Todo : (prop: { key: number; todo: string;}) => JSX.Element +>prop : { key: number; todo: string; } +>key : number +>todo : string + + return
{prop.key.toString() + prop.todo}
; +>
{prop.key.toString() + prop.todo}
: JSX.Element +>div : any +>prop.key.toString() + prop.todo : string +>prop.key.toString() : string +>prop.key.toString : (radix?: number) => string +>prop.key : number +>prop : { key: number; todo: string; } +>key : number +>toString : (radix?: number) => string +>prop.todo : string +>prop : { key: number; todo: string; } +>todo : string +>div : any +} +function TodoList({ todos }: TodoListProps) { +>TodoList : ({ todos }: TodoListProps) => JSX.Element +>todos : TodoProp[] + + return
+>
{...}
: JSX.Element +>div : any + + {...} +> : JSX.Element +>Todo : (prop: { key: number; todo: string; }) => JSX.Element +>key : number +>todos[0].id : number +>todos[0] : TodoProp +>todos : TodoProp[] +>0 : 0 +>id : number +>todo : string +>todos[0].todo : string +>todos[0] : TodoProp +>todos : TodoProp[] +>0 : 0 +>todo : string + +
; +>div : any +} +function TodoListNoError({ todos }: TodoListProps) { +>TodoListNoError : ({ todos }: TodoListProps) => JSX.Element +>todos : TodoProp[] + + // any is not checked + return
+>
{...( as any)}
: JSX.Element +>div : any + + {...( as any)} +>( as any) : any +> as any : any +> : JSX.Element +>Todo : (prop: { key: number; todo: string; }) => JSX.Element +>key : number +>todos[0].id : number +>todos[0] : TodoProp +>todos : TodoProp[] +>0 : 0 +>id : number +>todo : string +>todos[0].todo : string +>todos[0] : TodoProp +>todos : TodoProp[] +>0 : 0 +>todo : string + +
; +>div : any +} +let x: TodoListProps; +>x : TodoListProps + + +> : JSX.Element +>TodoList : ({ todos }: TodoListProps) => JSX.Element +>x : TodoListProps + diff --git a/tests/cases/conformance/jsx/tsxSpreadChildrenInvalidType.tsx b/tests/cases/conformance/jsx/tsxSpreadChildrenInvalidType.tsx index 41181618ce0a3..49067bbc4b02e 100644 --- a/tests/cases/conformance/jsx/tsxSpreadChildrenInvalidType.tsx +++ b/tests/cases/conformance/jsx/tsxSpreadChildrenInvalidType.tsx @@ -1,4 +1,5 @@ // @jsx: react +// @target: es2015,es5 declare module JSX { interface Element { } interface IntrinsicElements {