diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 12b55aa818b..5fe3a0de1a5 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -12754,11 +12754,6 @@ namespace ts { // Props is of type 'any' or unknown return attributesType; } - else if (attributesType.flags & TypeFlags.Union) { - // Props cannot be a union type - error(openingLikeElement.tagName, Diagnostics.JSX_element_attributes_type_0_may_not_be_a_union_type, typeToString(attributesType)); - return anyType; - } else { // Normal case -- add in IntrinsicClassElements and IntrinsicElements let apparentAttributesType = attributesType; diff --git a/tests/baselines/reference/tsxAttributeResolution16.js b/tests/baselines/reference/tsxAttributeResolution16.js new file mode 100644 index 00000000000..1182c886b94 --- /dev/null +++ b/tests/baselines/reference/tsxAttributeResolution16.js @@ -0,0 +1,53 @@ +//// [file.tsx] + +import React = require('react'); + +interface Address { + street: string; + country: string; +} + +interface CanadianAddress extends Address { + postalCode: string; +} + +interface AmericanAddress extends Address { + zipCode: string; +} + +type Properties = CanadianAddress | AmericanAddress; + +export class AddressComp extends React.Component { + public render() { + return null; + } +} + +let a = + +//// [file.jsx] +"use strict"; +var __extends = (this && this.__extends) || (function () { + var extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +exports.__esModule = true; +var React = require("react"); +var AddressComp = (function (_super) { + __extends(AddressComp, _super); + function AddressComp() { + return _super !== null && _super.apply(this, arguments) || this; + } + AddressComp.prototype.render = function () { + return null; + }; + return AddressComp; +}(React.Component)); +exports.AddressComp = AddressComp; +var a = ; diff --git a/tests/baselines/reference/tsxAttributeResolution16.symbols b/tests/baselines/reference/tsxAttributeResolution16.symbols new file mode 100644 index 00000000000..0c271566de9 --- /dev/null +++ b/tests/baselines/reference/tsxAttributeResolution16.symbols @@ -0,0 +1,57 @@ +=== tests/cases/conformance/jsx/file.tsx === + +import React = require('react'); +>React : Symbol(React, Decl(file.tsx, 0, 0)) + +interface Address { +>Address : Symbol(Address, Decl(file.tsx, 1, 32)) + + street: string; +>street : Symbol(Address.street, Decl(file.tsx, 3, 19)) + + country: string; +>country : Symbol(Address.country, Decl(file.tsx, 4, 17)) +} + +interface CanadianAddress extends Address { +>CanadianAddress : Symbol(CanadianAddress, Decl(file.tsx, 6, 1)) +>Address : Symbol(Address, Decl(file.tsx, 1, 32)) + + postalCode: string; +>postalCode : Symbol(CanadianAddress.postalCode, Decl(file.tsx, 8, 43)) +} + +interface AmericanAddress extends Address { +>AmericanAddress : Symbol(AmericanAddress, Decl(file.tsx, 10, 1)) +>Address : Symbol(Address, Decl(file.tsx, 1, 32)) + + zipCode: string; +>zipCode : Symbol(AmericanAddress.zipCode, Decl(file.tsx, 12, 43)) +} + +type Properties = CanadianAddress | AmericanAddress; +>Properties : Symbol(Properties, Decl(file.tsx, 14, 1)) +>CanadianAddress : Symbol(CanadianAddress, Decl(file.tsx, 6, 1)) +>AmericanAddress : Symbol(AmericanAddress, Decl(file.tsx, 10, 1)) + +export class AddressComp extends React.Component { +>AddressComp : Symbol(AddressComp, Decl(file.tsx, 16, 52)) +>React.Component : Symbol(React.Component, Decl(react.d.ts, 158, 55)) +>React : Symbol(React, Decl(file.tsx, 0, 0)) +>Component : Symbol(React.Component, Decl(react.d.ts, 158, 55)) +>Properties : Symbol(Properties, Decl(file.tsx, 14, 1)) + + public render() { +>render : Symbol(AddressComp.render, Decl(file.tsx, 18, 68)) + + return null; + } +} + +let a = +>a : Symbol(a, Decl(file.tsx, 24, 3)) +>AddressComp : Symbol(AddressComp, Decl(file.tsx, 16, 52)) +>postalCode : Symbol(postalCode, Decl(file.tsx, 24, 20)) +>street : Symbol(street, Decl(file.tsx, 24, 41)) +>country : Symbol(country, Decl(file.tsx, 24, 60)) + diff --git a/tests/baselines/reference/tsxAttributeResolution16.types b/tests/baselines/reference/tsxAttributeResolution16.types new file mode 100644 index 00000000000..68134d7ac2d --- /dev/null +++ b/tests/baselines/reference/tsxAttributeResolution16.types @@ -0,0 +1,59 @@ +=== tests/cases/conformance/jsx/file.tsx === + +import React = require('react'); +>React : typeof React + +interface Address { +>Address : Address + + street: string; +>street : string + + country: string; +>country : string +} + +interface CanadianAddress extends Address { +>CanadianAddress : CanadianAddress +>Address : Address + + postalCode: string; +>postalCode : string +} + +interface AmericanAddress extends Address { +>AmericanAddress : AmericanAddress +>Address : Address + + zipCode: string; +>zipCode : string +} + +type Properties = CanadianAddress | AmericanAddress; +>Properties : CanadianAddress | AmericanAddress +>CanadianAddress : CanadianAddress +>AmericanAddress : AmericanAddress + +export class AddressComp extends React.Component { +>AddressComp : AddressComp +>React.Component : React.Component +>React : typeof React +>Component : typeof React.Component +>Properties : CanadianAddress | AmericanAddress + + public render() { +>render : () => any + + return null; +>null : null + } +} + +let a = +>a : JSX.Element +> : JSX.Element +>AddressComp : typeof AddressComp +>postalCode : string +>street : string +>country : string + diff --git a/tests/baselines/reference/tsxSpreadAttributesResolution6.errors.txt b/tests/baselines/reference/tsxSpreadAttributesResolution6.errors.txt index c3bd7484fbf..968fa3764a8 100644 --- a/tests/baselines/reference/tsxSpreadAttributesResolution6.errors.txt +++ b/tests/baselines/reference/tsxSpreadAttributesResolution6.errors.txt @@ -1,4 +1,7 @@ -tests/cases/conformance/jsx/file.tsx(14,10): error TS2600: JSX element attributes type '({ editable: false; } & { children?: ReactNode; }) | ({ editable: true; onEdit: (newText: string) => void; } & { children?: ReactNode; })' may not be a union type. +tests/cases/conformance/jsx/file.tsx(14,24): error TS2322: Type '{ editable: true; }' is not assignable to type '(IntrinsicAttributes & IntrinsicClassAttributes & { editable: false; } & { children?: ReactNode; }) | (IntrinsicAttributes & IntrinsicClassAttributes & { editable: true; onEdit: (newText: string) => void; } & { children?: ReactNode; })'. + Type '{ editable: true; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes & { editable: true; onEdit: (newText: string) => void; } & { children?: ReactNode; }'. + Type '{ editable: true; }' is not assignable to type '{ editable: true; onEdit: (newText: string) => void; }'. + Property 'onEdit' is missing in type '{ editable: true; }'. ==== tests/cases/conformance/jsx/file.tsx (1 errors) ==== @@ -16,8 +19,11 @@ tests/cases/conformance/jsx/file.tsx(14,10): error TS2600: JSX element attribute // Error let x = - ~~~~~~~~~~~~~ -!!! error TS2600: JSX element attributes type '({ editable: false; } & { children?: ReactNode; }) | ({ editable: true; onEdit: (newText: string) => void; } & { children?: ReactNode; })' may not be a union type. + ~~~~~~~~~~~~~~~ +!!! error TS2322: Type '{ editable: true; }' is not assignable to type '(IntrinsicAttributes & IntrinsicClassAttributes & { editable: false; } & { children?: ReactNode; }) | (IntrinsicAttributes & IntrinsicClassAttributes & { editable: true; onEdit: (newText: string) => void; } & { children?: ReactNode; })'. +!!! error TS2322: Type '{ editable: true; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes & { editable: true; onEdit: (newText: string) => void; } & { children?: ReactNode; }'. +!!! error TS2322: Type '{ editable: true; }' is not assignable to type '{ editable: true; onEdit: (newText: string) => void; }'. +!!! error TS2322: Property 'onEdit' is missing in type '{ editable: true; }'. const textProps: TextProps = { editable: false diff --git a/tests/baselines/reference/tsxSpreadAttributesResolution7.errors.txt b/tests/baselines/reference/tsxSpreadAttributesResolution7.errors.txt deleted file mode 100644 index c71459c4a38..00000000000 --- a/tests/baselines/reference/tsxSpreadAttributesResolution7.errors.txt +++ /dev/null @@ -1,34 +0,0 @@ -tests/cases/conformance/jsx/file.tsx(18,11): error TS2600: JSX element attributes type '({ editable: false; } & { children?: ReactNode; }) | ({ editable: true; onEdit: (newText: string) => void; } & { children?: ReactNode; })' may not be a union type. -tests/cases/conformance/jsx/file.tsx(25,11): error TS2600: JSX element attributes type '({ editable: false; } & { children?: ReactNode; }) | ({ editable: true; onEdit: (newText: string) => void; } & { children?: ReactNode; })' may not be a union type. - - -==== tests/cases/conformance/jsx/file.tsx (2 errors) ==== - - import React = require('react'); - - type TextProps = { editable: false } - | { editable: true, onEdit: (newText: string) => void }; - - class TextComponent extends React.Component { - render() { - return Some Text..; - } - } - - // OK - const textPropsFalse: TextProps = { - editable: false - }; - - let y1 = - ~~~~~~~~~~~~~ -!!! error TS2600: JSX element attributes type '({ editable: false; } & { children?: ReactNode; }) | ({ editable: true; onEdit: (newText: string) => void; } & { children?: ReactNode; })' may not be a union type. - - const textPropsTrue: TextProps = { - editable: true, - onEdit: () => {} - }; - - let y2 = - ~~~~~~~~~~~~~ -!!! error TS2600: JSX element attributes type '({ editable: false; } & { children?: ReactNode; }) | ({ editable: true; onEdit: (newText: string) => void; } & { children?: ReactNode; })' may not be a union type. \ No newline at end of file diff --git a/tests/baselines/reference/tsxSpreadAttributesResolution7.symbols b/tests/baselines/reference/tsxSpreadAttributesResolution7.symbols new file mode 100644 index 00000000000..f40b79ae616 --- /dev/null +++ b/tests/baselines/reference/tsxSpreadAttributesResolution7.symbols @@ -0,0 +1,62 @@ +=== tests/cases/conformance/jsx/file.tsx === + +import React = require('react'); +>React : Symbol(React, Decl(file.tsx, 0, 0)) + +type TextProps = { editable: false } +>TextProps : Symbol(TextProps, Decl(file.tsx, 1, 32)) +>editable : Symbol(editable, Decl(file.tsx, 3, 18)) + + | { editable: true, onEdit: (newText: string) => void }; +>editable : Symbol(editable, Decl(file.tsx, 4, 18)) +>onEdit : Symbol(onEdit, Decl(file.tsx, 4, 34)) +>newText : Symbol(newText, Decl(file.tsx, 4, 44)) + +class TextComponent extends React.Component { +>TextComponent : Symbol(TextComponent, Decl(file.tsx, 4, 71)) +>React.Component : Symbol(React.Component, Decl(react.d.ts, 158, 55)) +>React : Symbol(React, Decl(file.tsx, 0, 0)) +>Component : Symbol(React.Component, Decl(react.d.ts, 158, 55)) +>TextProps : Symbol(TextProps, Decl(file.tsx, 1, 32)) + + render() { +>render : Symbol(TextComponent.render, Decl(file.tsx, 6, 60)) + + return Some Text..; +>span : Symbol(JSX.IntrinsicElements.span, Decl(react.d.ts, 2458, 51)) +>span : Symbol(JSX.IntrinsicElements.span, Decl(react.d.ts, 2458, 51)) + } +} + +// OK +const textPropsFalse: TextProps = { +>textPropsFalse : Symbol(textPropsFalse, Decl(file.tsx, 13, 5)) +>TextProps : Symbol(TextProps, Decl(file.tsx, 1, 32)) + + editable: false +>editable : Symbol(editable, Decl(file.tsx, 13, 35)) + +}; + +let y1 = +>y1 : Symbol(y1, Decl(file.tsx, 17, 3)) +>TextComponent : Symbol(TextComponent, Decl(file.tsx, 4, 71)) +>textPropsFalse : Symbol(textPropsFalse, Decl(file.tsx, 13, 5)) + +const textPropsTrue: TextProps = { +>textPropsTrue : Symbol(textPropsTrue, Decl(file.tsx, 19, 5)) +>TextProps : Symbol(TextProps, Decl(file.tsx, 1, 32)) + + editable: true, +>editable : Symbol(editable, Decl(file.tsx, 19, 34)) + + onEdit: () => {} +>onEdit : Symbol(onEdit, Decl(file.tsx, 20, 19)) + +}; + +let y2 = +>y2 : Symbol(y2, Decl(file.tsx, 24, 3)) +>TextComponent : Symbol(TextComponent, Decl(file.tsx, 4, 71)) +>textPropsTrue : Symbol(textPropsTrue, Decl(file.tsx, 19, 5)) + diff --git a/tests/baselines/reference/tsxSpreadAttributesResolution7.types b/tests/baselines/reference/tsxSpreadAttributesResolution7.types new file mode 100644 index 00000000000..db423de0904 --- /dev/null +++ b/tests/baselines/reference/tsxSpreadAttributesResolution7.types @@ -0,0 +1,72 @@ +=== tests/cases/conformance/jsx/file.tsx === + +import React = require('react'); +>React : typeof React + +type TextProps = { editable: false } +>TextProps : { editable: false; } | { editable: true; onEdit: (newText: string) => void; } +>editable : false +>false : false + + | { editable: true, onEdit: (newText: string) => void }; +>editable : true +>true : true +>onEdit : (newText: string) => void +>newText : string + +class TextComponent extends React.Component { +>TextComponent : TextComponent +>React.Component : React.Component<{ editable: false; } | { editable: true; onEdit: (newText: string) => void; }, {}> +>React : typeof React +>Component : typeof React.Component +>TextProps : { editable: false; } | { editable: true; onEdit: (newText: string) => void; } + + render() { +>render : () => JSX.Element + + return Some Text..; +>Some Text.. : JSX.Element +>span : any +>span : any + } +} + +// OK +const textPropsFalse: TextProps = { +>textPropsFalse : { editable: false; } | { editable: true; onEdit: (newText: string) => void; } +>TextProps : { editable: false; } | { editable: true; onEdit: (newText: string) => void; } +>{ editable: false} : { editable: false; } + + editable: false +>editable : boolean +>false : false + +}; + +let y1 = +>y1 : JSX.Element +> : JSX.Element +>TextComponent : typeof TextComponent +>textPropsFalse : { editable: false; } + +const textPropsTrue: TextProps = { +>textPropsTrue : { editable: false; } | { editable: true; onEdit: (newText: string) => void; } +>TextProps : { editable: false; } | { editable: true; onEdit: (newText: string) => void; } +>{ editable: true, onEdit: () => {}} : { editable: true; onEdit: () => void; } + + editable: true, +>editable : boolean +>true : true + + onEdit: () => {} +>onEdit : () => void +>() => {} : () => void + +}; + +let y2 = +>y2 : JSX.Element +> : JSX.Element +>TextComponent : typeof TextComponent +>textPropsTrue : { editable: true; onEdit: (newText: string) => void; } + diff --git a/tests/cases/conformance/jsx/tsxAttributeResolution16.tsx b/tests/cases/conformance/jsx/tsxAttributeResolution16.tsx new file mode 100644 index 00000000000..811a1b47174 --- /dev/null +++ b/tests/cases/conformance/jsx/tsxAttributeResolution16.tsx @@ -0,0 +1,29 @@ +// @filename: file.tsx +// @jsx: preserve +// @noLib: true +// @libFiles: react.d.ts,lib.d.ts + +import React = require('react'); + +interface Address { + street: string; + country: string; +} + +interface CanadianAddress extends Address { + postalCode: string; +} + +interface AmericanAddress extends Address { + zipCode: string; +} + +type Properties = CanadianAddress | AmericanAddress; + +export class AddressComp extends React.Component { + public render() { + return null; + } +} + +let a = \ No newline at end of file