From 1f19fd69b15704f1959f68625d73be28f8f9ea0d Mon Sep 17 00:00:00 2001 From: Yui T Date: Tue, 2 May 2017 20:54:27 -0700 Subject: [PATCH 1/3] Don't stop checking other attributes even though we see spread type. This is so that things are correctly marked as reference and type-checked --- src/compiler/checker.ts | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) 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. From c6ece969f0dd4bd44ed28f7aba6fdbedb77ca382 Mon Sep 17 00:00:00 2001 From: Yui T Date: Tue, 2 May 2017 20:54:42 -0700 Subject: [PATCH 2/3] Update baseline --- ...atelessFunctionComponentsWithTypeArguments3.errors.txt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/baselines/reference/tsxStatelessFunctionComponentsWithTypeArguments3.errors.txt b/tests/baselines/reference/tsxStatelessFunctionComponentsWithTypeArguments3.errors.txt index 1d03542738fc0..fdf65ca1746be 100644 --- a/tests/baselines/reference/tsxStatelessFunctionComponentsWithTypeArguments3.errors.txt +++ b/tests/baselines/reference/tsxStatelessFunctionComponentsWithTypeArguments3.errors.txt @@ -3,10 +3,12 @@ tests/cases/conformance/jsx/file.tsx(10,33): error TS2698: Spread types may only tests/cases/conformance/jsx/file.tsx(11,33): error TS2698: Spread types may only be created from object types. tests/cases/conformance/jsx/file.tsx(12,33): error TS2698: Spread types may only be created from object types. tests/cases/conformance/jsx/file.tsx(14,33): error TS2698: Spread types may only be created from object types. +tests/cases/conformance/jsx/file.tsx(14,63): error TS2698: Spread types may only be created from object types. tests/cases/conformance/jsx/file.tsx(15,33): error TS2698: Spread types may only be created from object types. +tests/cases/conformance/jsx/file.tsx(15,55): error TS2698: Spread types may only be created from object types. -==== tests/cases/conformance/jsx/file.tsx (6 errors) ==== +==== tests/cases/conformance/jsx/file.tsx (8 errors) ==== import React = require('react') declare function OverloadComponent(): JSX.Element; @@ -30,9 +32,13 @@ tests/cases/conformance/jsx/file.tsx(15,33): error TS2698: Spread types may only let a4 = ; let a5 = ; ~~~~~~~~~ +!!! error TS2698: Spread types may only be created from object types. + ~~~~~~~~~ !!! error TS2698: Spread types may only be created from object types. let a6 = ; ~~~~~~~~~ +!!! error TS2698: Spread types may only be created from object types. + ~~~~~~~~~ !!! error TS2698: Spread types may only be created from object types. } From b77c0ad7417705ad4cdb4a1ab0a7bfdd568b9abb Mon Sep 17 00:00:00 2001 From: Yui T Date: Wed, 3 May 2017 13:30:30 -0700 Subject: [PATCH 3/3] Add tests and update baselines --- .../correctlyMarkAliasAsReferences1.js | 23 ++++++++++++ .../correctlyMarkAliasAsReferences1.symbols | 29 +++++++++++++++ .../correctlyMarkAliasAsReferences1.types | 35 ++++++++++++++++++ .../correctlyMarkAliasAsReferences2.js | 23 ++++++++++++ .../correctlyMarkAliasAsReferences2.symbols | 30 ++++++++++++++++ .../correctlyMarkAliasAsReferences2.types | 36 +++++++++++++++++++ .../correctlyMarkAliasAsReferences3.js | 23 ++++++++++++ .../correctlyMarkAliasAsReferences3.symbols | 29 +++++++++++++++ .../correctlyMarkAliasAsReferences3.types | 35 ++++++++++++++++++ .../correctlyMarkAliasAsReferences4.js | 19 ++++++++++ .../correctlyMarkAliasAsReferences4.symbols | 24 +++++++++++++ .../correctlyMarkAliasAsReferences4.types | 29 +++++++++++++++ .../jsx/correctlyMarkAliasAsReferences1.tsx | 17 +++++++++ .../jsx/correctlyMarkAliasAsReferences2.tsx | 17 +++++++++ .../jsx/correctlyMarkAliasAsReferences3.tsx | 18 ++++++++++ .../jsx/correctlyMarkAliasAsReferences4.tsx | 15 ++++++++ tests/lib/react.d.ts | 4 +-- 17 files changed, 404 insertions(+), 2 deletions(-) create mode 100644 tests/baselines/reference/correctlyMarkAliasAsReferences1.js create mode 100644 tests/baselines/reference/correctlyMarkAliasAsReferences1.symbols create mode 100644 tests/baselines/reference/correctlyMarkAliasAsReferences1.types create mode 100644 tests/baselines/reference/correctlyMarkAliasAsReferences2.js create mode 100644 tests/baselines/reference/correctlyMarkAliasAsReferences2.symbols create mode 100644 tests/baselines/reference/correctlyMarkAliasAsReferences2.types create mode 100644 tests/baselines/reference/correctlyMarkAliasAsReferences3.js create mode 100644 tests/baselines/reference/correctlyMarkAliasAsReferences3.symbols create mode 100644 tests/baselines/reference/correctlyMarkAliasAsReferences3.types create mode 100644 tests/baselines/reference/correctlyMarkAliasAsReferences4.js create mode 100644 tests/baselines/reference/correctlyMarkAliasAsReferences4.symbols create mode 100644 tests/baselines/reference/correctlyMarkAliasAsReferences4.types create mode 100644 tests/cases/conformance/jsx/correctlyMarkAliasAsReferences1.tsx create mode 100644 tests/cases/conformance/jsx/correctlyMarkAliasAsReferences2.tsx create mode 100644 tests/cases/conformance/jsx/correctlyMarkAliasAsReferences3.tsx create mode 100644 tests/cases/conformance/jsx/correctlyMarkAliasAsReferences4.tsx 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 =