diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 2d18c7270868a..65a34bec1d47f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -13211,6 +13211,8 @@ namespace ts { let attributesTable = createMap(); let spread: Type = emptyObjectType; let attributesArray: Symbol[] = []; + let hasSpreadAnyType = false; + for (const attributeDecl of attributes.properties) { const member = attributeDecl.symbol; if (isJsxAttribute(attributeDecl)) { @@ -13239,31 +13241,33 @@ namespace ts { const exprType = checkExpression(attributeDecl.expression); if (!isValidSpreadType(exprType)) { error(attributeDecl, Diagnostics.Spread_types_may_only_be_created_from_object_types); - return anyType; + hasSpreadAnyType = true; } if (isTypeAny(exprType)) { - return anyType; + hasSpreadAnyType = true; } spread = getSpreadType(spread, exprType); } } - if (spread !== emptyObjectType) { - if (attributesArray.length > 0) { - spread = getSpreadType(spread, createJsxAttributesType(attributes.symbol, attributesTable)); - attributesArray = []; - attributesTable = createMap(); + if (!hasSpreadAnyType) { + if (spread !== emptyObjectType) { + if (attributesArray.length > 0) { + spread = getSpreadType(spread, createJsxAttributesType(attributes.symbol, attributesTable)); + attributesArray = []; + attributesTable = createMap(); + } + attributesArray = getPropertiesOfType(spread); } - attributesArray = getPropertiesOfType(spread); - } - attributesTable = createMap(); - if (attributesArray) { - forEach(attributesArray, (attr) => { - if (!filter || filter(attr)) { - attributesTable.set(attr.name, attr); - } - }); + attributesTable = createMap(); + if (attributesArray) { + forEach(attributesArray, (attr) => { + if (!filter || filter(attr)) { + attributesTable.set(attr.name, attr); + } + }); + } } // Handle children attribute @@ -13287,7 +13291,7 @@ namespace ts { // Error if there is a attribute named "children" and children element. // This is because children element will overwrite the value from attributes const jsxChildrenPropertyName = getJsxElementChildrenPropertyname(); - if (jsxChildrenPropertyName && jsxChildrenPropertyName !== "") { + if (!hasSpreadAnyType && jsxChildrenPropertyName && jsxChildrenPropertyName !== "") { if (attributesTable.has(jsxChildrenPropertyName)) { error(attributes, Diagnostics._0_are_specified_twice_The_attribute_named_0_will_be_overwritten, jsxChildrenPropertyName); } @@ -13301,7 +13305,7 @@ namespace ts { } } - return createJsxAttributesType(attributes.symbol, attributesTable); + return hasSpreadAnyType ? anyType : createJsxAttributesType(attributes.symbol, attributesTable); /** * Create anonymous type from given attributes symbol table. diff --git a/tests/baselines/reference/correctlyMarkAliasAsReferences1.js b/tests/baselines/reference/correctlyMarkAliasAsReferences1.js new file mode 100644 index 0000000000000..7816881f4a2ae --- /dev/null +++ b/tests/baselines/reference/correctlyMarkAliasAsReferences1.js @@ -0,0 +1,23 @@ +//// [tests/cases/conformance/jsx/correctlyMarkAliasAsReferences1.tsx] //// + +//// [declaration.d.ts] +declare module "classnames"; + +//// [0.tsx] +/// +import * as cx from 'classnames'; +import * as React from "react"; + +let buttonProps; // any +let k = ; + + +//// [0.js] +/// +import * as cx from 'classnames'; +import * as React from "react"; +let buttonProps; // any +let k = React.createElement("button", Object.assign({}, buttonProps), + React.createElement("span", { className: cx('class1', { class2: true }) })); diff --git a/tests/baselines/reference/correctlyMarkAliasAsReferences1.symbols b/tests/baselines/reference/correctlyMarkAliasAsReferences1.symbols new file mode 100644 index 0000000000000..3267a29050e11 --- /dev/null +++ b/tests/baselines/reference/correctlyMarkAliasAsReferences1.symbols @@ -0,0 +1,29 @@ +=== tests/cases/conformance/jsx/0.tsx === +/// +import * as cx from 'classnames'; +>cx : Symbol(cx, Decl(0.tsx, 1, 6)) + +import * as React from "react"; +>React : Symbol(React, Decl(0.tsx, 2, 6)) + +let buttonProps; // any +>buttonProps : Symbol(buttonProps, Decl(0.tsx, 4, 3)) + +let k = ; +>button : Symbol(JSX.IntrinsicElements.button, Decl(react.d.ts, 2385, 43)) + +=== tests/cases/conformance/jsx/declaration.d.ts === +declare module "classnames"; +No type information for this code. +No type information for this code. \ No newline at end of file diff --git a/tests/baselines/reference/correctlyMarkAliasAsReferences1.types b/tests/baselines/reference/correctlyMarkAliasAsReferences1.types new file mode 100644 index 0000000000000..dbcad2fdc3c99 --- /dev/null +++ b/tests/baselines/reference/correctlyMarkAliasAsReferences1.types @@ -0,0 +1,35 @@ +=== tests/cases/conformance/jsx/0.tsx === +/// +import * as cx from 'classnames'; +>cx : any + +import * as React from "react"; +>React : typeof React + +let buttonProps; // any +>buttonProps : any + +let k = : JSX.Element +>button : any +>buttonProps : any + + +> : JSX.Element +>span : any +>className : any +>cx('class1', { class2: true }) : any +>cx : any +>'class1' : "class1" +>{ class2: true } : { class2: boolean; } +>class2 : boolean +>true : true + + ; +>button : any + +=== tests/cases/conformance/jsx/declaration.d.ts === +declare module "classnames"; +No type information for this code. +No type information for this code. \ No newline at end of file diff --git a/tests/baselines/reference/correctlyMarkAliasAsReferences2.js b/tests/baselines/reference/correctlyMarkAliasAsReferences2.js new file mode 100644 index 0000000000000..7af59b017a8ee --- /dev/null +++ b/tests/baselines/reference/correctlyMarkAliasAsReferences2.js @@ -0,0 +1,23 @@ +//// [tests/cases/conformance/jsx/correctlyMarkAliasAsReferences2.tsx] //// + +//// [declaration.d.ts] +declare module "classnames"; + +//// [0.tsx] +/// +import * as cx from 'classnames'; +import * as React from "react"; + +let buttonProps : {[attributeName: string]: ''} +let k = ; + + +//// [0.js] +/// +import * as cx from 'classnames'; +import * as React from "react"; +let buttonProps; +let k = React.createElement("button", Object.assign({}, buttonProps), + React.createElement("span", { className: cx('class1', { class2: true }) })); diff --git a/tests/baselines/reference/correctlyMarkAliasAsReferences2.symbols b/tests/baselines/reference/correctlyMarkAliasAsReferences2.symbols new file mode 100644 index 0000000000000..76d9b8cdfe076 --- /dev/null +++ b/tests/baselines/reference/correctlyMarkAliasAsReferences2.symbols @@ -0,0 +1,30 @@ +=== tests/cases/conformance/jsx/0.tsx === +/// +import * as cx from 'classnames'; +>cx : Symbol(cx, Decl(0.tsx, 1, 6)) + +import * as React from "react"; +>React : Symbol(React, Decl(0.tsx, 2, 6)) + +let buttonProps : {[attributeName: string]: ''} +>buttonProps : Symbol(buttonProps, Decl(0.tsx, 4, 3)) +>attributeName : Symbol(attributeName, Decl(0.tsx, 4, 20)) + +let k = ; +>button : Symbol(JSX.IntrinsicElements.button, Decl(react.d.ts, 2385, 43)) + +=== tests/cases/conformance/jsx/declaration.d.ts === +declare module "classnames"; +No type information for this code. +No type information for this code. \ No newline at end of file diff --git a/tests/baselines/reference/correctlyMarkAliasAsReferences2.types b/tests/baselines/reference/correctlyMarkAliasAsReferences2.types new file mode 100644 index 0000000000000..cfaba960da2a3 --- /dev/null +++ b/tests/baselines/reference/correctlyMarkAliasAsReferences2.types @@ -0,0 +1,36 @@ +=== tests/cases/conformance/jsx/0.tsx === +/// +import * as cx from 'classnames'; +>cx : any + +import * as React from "react"; +>React : typeof React + +let buttonProps : {[attributeName: string]: ''} +>buttonProps : { [attributeName: string]: ""; } +>attributeName : string + +let k = : JSX.Element +>button : any +>buttonProps : { [attributeName: string]: ""; } + + +> : JSX.Element +>span : any +>className : any +>cx('class1', { class2: true }) : any +>cx : any +>'class1' : "class1" +>{ class2: true } : { class2: boolean; } +>class2 : boolean +>true : true + + ; +>button : any + +=== tests/cases/conformance/jsx/declaration.d.ts === +declare module "classnames"; +No type information for this code. +No type information for this code. \ No newline at end of file diff --git a/tests/baselines/reference/correctlyMarkAliasAsReferences3.js b/tests/baselines/reference/correctlyMarkAliasAsReferences3.js new file mode 100644 index 0000000000000..166e29d56dbb9 --- /dev/null +++ b/tests/baselines/reference/correctlyMarkAliasAsReferences3.js @@ -0,0 +1,23 @@ +//// [tests/cases/conformance/jsx/correctlyMarkAliasAsReferences3.tsx] //// + +//// [declaration.d.ts] +declare module "classnames"; + +//// [0.tsx] +/// +import * as cx from 'classnames'; +import * as React from "react"; + +let buttonProps; +let k = ; + + +//// [0.js] +/// +import * as cx from 'classnames'; +import * as React from "react"; +let buttonProps; +let k = React.createElement("button", Object.assign({}, buttonProps), + React.createElement("span", { className: cx('class1', { class2: true }) })); diff --git a/tests/baselines/reference/correctlyMarkAliasAsReferences3.symbols b/tests/baselines/reference/correctlyMarkAliasAsReferences3.symbols new file mode 100644 index 0000000000000..088f553baa495 --- /dev/null +++ b/tests/baselines/reference/correctlyMarkAliasAsReferences3.symbols @@ -0,0 +1,29 @@ +=== tests/cases/conformance/jsx/0.tsx === +/// +import * as cx from 'classnames'; +>cx : Symbol(cx, Decl(0.tsx, 1, 6)) + +import * as React from "react"; +>React : Symbol(React, Decl(0.tsx, 2, 6)) + +let buttonProps; +>buttonProps : Symbol(buttonProps, Decl(0.tsx, 4, 3)) + +let k = ; +>button : Symbol(JSX.IntrinsicElements.button, Decl(react.d.ts, 2385, 43)) + +=== tests/cases/conformance/jsx/declaration.d.ts === +declare module "classnames"; +No type information for this code. +No type information for this code. \ No newline at end of file diff --git a/tests/baselines/reference/correctlyMarkAliasAsReferences3.types b/tests/baselines/reference/correctlyMarkAliasAsReferences3.types new file mode 100644 index 0000000000000..cca59ae2f5eef --- /dev/null +++ b/tests/baselines/reference/correctlyMarkAliasAsReferences3.types @@ -0,0 +1,35 @@ +=== tests/cases/conformance/jsx/0.tsx === +/// +import * as cx from 'classnames'; +>cx : any + +import * as React from "react"; +>React : typeof React + +let buttonProps; +>buttonProps : any + +let k = : JSX.Element +>button : any +>buttonProps : undefined + + +> : JSX.Element +>span : any +>className : any +>cx('class1', { class2: true }) : any +>cx : any +>'class1' : "class1" +>{ class2: true } : { class2: boolean; } +>class2 : boolean +>true : true + + ; +>button : any + +=== tests/cases/conformance/jsx/declaration.d.ts === +declare module "classnames"; +No type information for this code. +No type information for this code. \ No newline at end of file diff --git a/tests/baselines/reference/correctlyMarkAliasAsReferences4.js b/tests/baselines/reference/correctlyMarkAliasAsReferences4.js new file mode 100644 index 0000000000000..631d06cc5b362 --- /dev/null +++ b/tests/baselines/reference/correctlyMarkAliasAsReferences4.js @@ -0,0 +1,19 @@ +//// [tests/cases/conformance/jsx/correctlyMarkAliasAsReferences4.tsx] //// + +//// [declaration.d.ts] +declare module "classnames"; + +//// [0.tsx] +/// +import * as cx from 'classnames'; +import * as React from "react"; + +let buttonProps : {[attributeName: string]: ''} +let k = ; diff --git a/tests/cases/conformance/jsx/correctlyMarkAliasAsReferences2.tsx b/tests/cases/conformance/jsx/correctlyMarkAliasAsReferences2.tsx new file mode 100644 index 0000000000000..9755c624fc5ac --- /dev/null +++ b/tests/cases/conformance/jsx/correctlyMarkAliasAsReferences2.tsx @@ -0,0 +1,17 @@ +// @target: es2017 +// @jsx: react +// @moduleResolution: node +// @libFiles: react.d.ts,lib.d.ts + +// @filename: declaration.d.ts +declare module "classnames"; + +// @filename: 0.tsx +/// +import * as cx from 'classnames'; +import * as React from "react"; + +let buttonProps : {[attributeName: string]: ''} +let k = ; diff --git a/tests/cases/conformance/jsx/correctlyMarkAliasAsReferences3.tsx b/tests/cases/conformance/jsx/correctlyMarkAliasAsReferences3.tsx new file mode 100644 index 0000000000000..c3bfb0c8a476d --- /dev/null +++ b/tests/cases/conformance/jsx/correctlyMarkAliasAsReferences3.tsx @@ -0,0 +1,18 @@ +// @target: es2017 +// @jsx: react +// @moduleResolution: node +// @noImplicitAny: true +// @libFiles: react.d.ts,lib.d.ts + +// @filename: declaration.d.ts +declare module "classnames"; + +// @filename: 0.tsx +/// +import * as cx from 'classnames'; +import * as React from "react"; + +let buttonProps; +let k = ; diff --git a/tests/cases/conformance/jsx/correctlyMarkAliasAsReferences4.tsx b/tests/cases/conformance/jsx/correctlyMarkAliasAsReferences4.tsx new file mode 100644 index 0000000000000..edb9f75f87be8 --- /dev/null +++ b/tests/cases/conformance/jsx/correctlyMarkAliasAsReferences4.tsx @@ -0,0 +1,15 @@ +// @target: es2017 +// @jsx: react +// @moduleResolution: node +// @libFiles: react.d.ts,lib.d.ts + +// @filename: declaration.d.ts +declare module "classnames"; + +// @filename: 0.tsx +/// +import * as cx from 'classnames'; +import * as React from "react"; + +let buttonProps : {[attributeName: string]: ''} +let k =