diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 78a7ccffbdd..09760b6b1e5 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3766,11 +3766,13 @@ namespace ts { function createUnionOrIntersectionProperty(containingType: UnionOrIntersectionType, name: string): Symbol { const types = containingType.types; let props: Symbol[]; + let isOptional = !!(containingType.flags & TypeFlags.Intersection); for (const current of types) { const type = getApparentType(current); if (type !== unknownType) { const prop = getPropertyOfType(type, name); if (prop && !(getDeclarationFlagsFromSymbol(prop) & (NodeFlags.Private | NodeFlags.Protected))) { + isOptional = isOptional && !!(prop.flags & SymbolFlags.Optional); if (!props) { props = [prop]; } @@ -3798,7 +3800,12 @@ namespace ts { } propTypes.push(getTypeOfSymbol(prop)); } - const result = createSymbol(SymbolFlags.Property | SymbolFlags.Transient | SymbolFlags.SyntheticProperty, name); + const result = createSymbol( + SymbolFlags.Property | + SymbolFlags.Transient | + SymbolFlags.SyntheticProperty | + (isOptional ? SymbolFlags.Optional : SymbolFlags.None), + name); result.containingType = containingType; result.declarations = declarations; result.type = containingType.flags & TypeFlags.Union ? getUnionType(propTypes) : getIntersectionType(propTypes); @@ -8232,9 +8239,9 @@ namespace ts { // Props is of type 'any' or unknown return links.resolvedJsxType = attributesType; } - else if (!(attributesType.flags & TypeFlags.ObjectType)) { - // Props is not an object type - error(node.tagName, Diagnostics.JSX_element_attributes_type_0_must_be_an_object_type, typeToString(attributesType)); + else if (attributesType.flags & TypeFlags.Union) { + // Props cannot be a union type + error(node.tagName, Diagnostics.JSX_element_attributes_type_0_may_not_be_a_union_type, typeToString(attributesType)); return links.resolvedJsxType = anyType; } else { diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 54123808932..1a2575e9da6 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -1691,7 +1691,7 @@ "category": "Error", "code": 2528 }, - "JSX element attributes type '{0}' must be an object type.": { + "JSX element attributes type '{0}' may not be a union type.": { "category": "Error", "code": 2600 }, diff --git a/tests/baselines/reference/tsxAttributeResolution11.errors.txt b/tests/baselines/reference/tsxAttributeResolution11.errors.txt new file mode 100644 index 00000000000..b043897d50d --- /dev/null +++ b/tests/baselines/reference/tsxAttributeResolution11.errors.txt @@ -0,0 +1,33 @@ +tests/cases/conformance/jsx/file.tsx(11,22): error TS2339: Property 'bar' does not exist on type 'IntrinsicAttributes & { ref?: string; }'. + + +==== tests/cases/conformance/jsx/react.d.ts (0 errors) ==== + + declare module JSX { + interface Element { } + interface IntrinsicElements { + } + interface ElementAttributesProperty { + props; + } + interface IntrinsicAttributes { + ref?: string; + } + } + +==== tests/cases/conformance/jsx/file.tsx (1 errors) ==== + class MyComponent { + render() { + } + + props: { + ref?: string; + } + } + + // Should be an OK + var x = ; + ~~~ +!!! error TS2339: Property 'bar' does not exist on type 'IntrinsicAttributes & { ref?: string; }'. + + \ No newline at end of file diff --git a/tests/baselines/reference/tsxAttributeResolution11.js b/tests/baselines/reference/tsxAttributeResolution11.js new file mode 100644 index 00000000000..03b843c209a --- /dev/null +++ b/tests/baselines/reference/tsxAttributeResolution11.js @@ -0,0 +1,41 @@ +//// [tests/cases/conformance/jsx/tsxAttributeResolution11.tsx] //// + +//// [react.d.ts] + +declare module JSX { + interface Element { } + interface IntrinsicElements { + } + interface ElementAttributesProperty { + props; + } + interface IntrinsicAttributes { + ref?: string; + } +} + +//// [file.tsx] +class MyComponent { + render() { + } + + props: { + ref?: string; + } +} + +// Should be an OK +var x = ; + + + +//// [file.jsx] +var MyComponent = (function () { + function MyComponent() { + } + MyComponent.prototype.render = function () { + }; + return MyComponent; +}()); +// Should be an OK +var x = ; diff --git a/tests/cases/conformance/jsx/tsxAttributeResolution11.tsx b/tests/cases/conformance/jsx/tsxAttributeResolution11.tsx new file mode 100644 index 00000000000..fdff3c36fc7 --- /dev/null +++ b/tests/cases/conformance/jsx/tsxAttributeResolution11.tsx @@ -0,0 +1,29 @@ +//@jsx: preserve +//@module: amd + +//@filename: react.d.ts +declare module JSX { + interface Element { } + interface IntrinsicElements { + } + interface ElementAttributesProperty { + props; + } + interface IntrinsicAttributes { + ref?: string; + } +} + +//@filename: file.tsx +class MyComponent { + render() { + } + + props: { + ref?: string; + } +} + +// Should be an OK +var x = ; +