Skip to content

Commit

Permalink
Merge pull request #15789 from Microsoft/master-fix15742
Browse files Browse the repository at this point in the history
[Master] fix15742
  • Loading branch information
mhegazy authored May 12, 2017
2 parents 1becbf4 + 8907c70 commit d68b436
Show file tree
Hide file tree
Showing 32 changed files with 950 additions and 5 deletions.
18 changes: 17 additions & 1 deletion src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13574,6 +13574,20 @@ namespace ts {
return _jsxElementChildrenPropertyName;
}

function getApparentTypeOfJsxPropsType(propsType: Type): Type {
if (!propsType) {
return undefined;
}
if (propsType.flags & TypeFlags.Intersection) {
const propsApparentType: Type[] = [];
for (const t of (<UnionOrIntersectionType>propsType).types) {
propsApparentType.push(getApparentType(t));
}
return getIntersectionType(propsApparentType);
}
return getApparentType(propsType);
}

/**
* Get JSX attributes type by trying to resolve openingLikeElement as a stateless function component.
* Return only attributes type of successfully resolved call signature.
Expand All @@ -13594,6 +13608,7 @@ namespace ts {
if (callSignature !== unknownSignature) {
const callReturnType = callSignature && getReturnTypeOfSignature(callSignature);
let paramType = callReturnType && (callSignature.parameters.length === 0 ? emptyObjectType : getTypeOfSymbol(callSignature.parameters[0]));
paramType = getApparentTypeOfJsxPropsType(paramType);
if (callReturnType && isTypeAssignableTo(callReturnType, jsxStatelessElementType)) {
// Intersect in JSX.IntrinsicAttributes if it exists
const intrinsicAttributes = getJsxType(JsxNames.IntrinsicAttributes);
Expand Down Expand Up @@ -13631,7 +13646,8 @@ namespace ts {
let allMatchingAttributesType: Type;
for (const candidate of candidatesOutArray) {
const callReturnType = getReturnTypeOfSignature(candidate);
const paramType = callReturnType && (candidate.parameters.length === 0 ? emptyObjectType : getTypeOfSymbol(candidate.parameters[0]));
let paramType = callReturnType && (candidate.parameters.length === 0 ? emptyObjectType : getTypeOfSymbol(candidate.parameters[0]));
paramType = getApparentTypeOfJsxPropsType(paramType);
if (callReturnType && isTypeAssignableTo(callReturnType, jsxStatelessElementType)) {
let shouldBeCandidate = true;
for (const attribute of openingLikeElement.attributes.properties) {
Expand Down
28 changes: 28 additions & 0 deletions tests/baselines/reference/tsxGenericAttributesType1.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//// [file.tsx]
import React = require('react');

const decorator = function <T>(Component: React.StatelessComponent<T>): React.StatelessComponent<T> {
return (props) => <Component {...props}></Component>
};

const decorator2 = function <T extends { x: number }>(Component: React.StatelessComponent<T>): React.StatelessComponent<T> {
return (props) => <Component {...props} x={2} ></Component>
};

const decorator3 = function <T extends { x: number }, U extends { x: number } >(Component: React.StatelessComponent<T>): React.StatelessComponent<T> {
return (props) => <Component x={2} {...props} ></Component>
};

//// [file.jsx]
"use strict";
exports.__esModule = true;
var React = require("react");
var decorator = function (Component) {
return function (props) { return <Component {...props}></Component>; };
};
var decorator2 = function (Component) {
return function (props) { return <Component {...props} x={2}></Component>; };
};
var decorator3 = function (Component) {
return function (props) { return <Component x={2} {...props}></Component>; };
};
66 changes: 66 additions & 0 deletions tests/baselines/reference/tsxGenericAttributesType1.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
=== tests/cases/conformance/jsx/file.tsx ===
import React = require('react');
>React : Symbol(React, Decl(file.tsx, 0, 0))

const decorator = function <T>(Component: React.StatelessComponent<T>): React.StatelessComponent<T> {
>decorator : Symbol(decorator, Decl(file.tsx, 2, 5))
>T : Symbol(T, Decl(file.tsx, 2, 28))
>Component : Symbol(Component, Decl(file.tsx, 2, 31))
>React : Symbol(React, Decl(file.tsx, 0, 0))
>StatelessComponent : Symbol(React.StatelessComponent, Decl(react.d.ts, 197, 40))
>T : Symbol(T, Decl(file.tsx, 2, 28))
>React : Symbol(React, Decl(file.tsx, 0, 0))
>StatelessComponent : Symbol(React.StatelessComponent, Decl(react.d.ts, 197, 40))
>T : Symbol(T, Decl(file.tsx, 2, 28))

return (props) => <Component {...props}></Component>
>props : Symbol(props, Decl(file.tsx, 3, 12))
>Component : Symbol(Component, Decl(file.tsx, 2, 31))
>props : Symbol(props, Decl(file.tsx, 3, 12))
>Component : Symbol(Component, Decl(file.tsx, 2, 31))

};

const decorator2 = function <T extends { x: number }>(Component: React.StatelessComponent<T>): React.StatelessComponent<T> {
>decorator2 : Symbol(decorator2, Decl(file.tsx, 6, 5))
>T : Symbol(T, Decl(file.tsx, 6, 29))
>x : Symbol(x, Decl(file.tsx, 6, 40))
>Component : Symbol(Component, Decl(file.tsx, 6, 54))
>React : Symbol(React, Decl(file.tsx, 0, 0))
>StatelessComponent : Symbol(React.StatelessComponent, Decl(react.d.ts, 197, 40))
>T : Symbol(T, Decl(file.tsx, 6, 29))
>React : Symbol(React, Decl(file.tsx, 0, 0))
>StatelessComponent : Symbol(React.StatelessComponent, Decl(react.d.ts, 197, 40))
>T : Symbol(T, Decl(file.tsx, 6, 29))

return (props) => <Component {...props} x={2} ></Component>
>props : Symbol(props, Decl(file.tsx, 7, 12))
>Component : Symbol(Component, Decl(file.tsx, 6, 54))
>props : Symbol(props, Decl(file.tsx, 7, 12))
>x : Symbol(x, Decl(file.tsx, 7, 43))
>Component : Symbol(Component, Decl(file.tsx, 6, 54))

};

const decorator3 = function <T extends { x: number }, U extends { x: number } >(Component: React.StatelessComponent<T>): React.StatelessComponent<T> {
>decorator3 : Symbol(decorator3, Decl(file.tsx, 10, 5))
>T : Symbol(T, Decl(file.tsx, 10, 29))
>x : Symbol(x, Decl(file.tsx, 10, 40))
>U : Symbol(U, Decl(file.tsx, 10, 53))
>x : Symbol(x, Decl(file.tsx, 10, 65))
>Component : Symbol(Component, Decl(file.tsx, 10, 80))
>React : Symbol(React, Decl(file.tsx, 0, 0))
>StatelessComponent : Symbol(React.StatelessComponent, Decl(react.d.ts, 197, 40))
>T : Symbol(T, Decl(file.tsx, 10, 29))
>React : Symbol(React, Decl(file.tsx, 0, 0))
>StatelessComponent : Symbol(React.StatelessComponent, Decl(react.d.ts, 197, 40))
>T : Symbol(T, Decl(file.tsx, 10, 29))

return (props) => <Component x={2} {...props} ></Component>
>props : Symbol(props, Decl(file.tsx, 11, 12))
>Component : Symbol(Component, Decl(file.tsx, 10, 80))
>x : Symbol(x, Decl(file.tsx, 11, 32))
>props : Symbol(props, Decl(file.tsx, 11, 12))
>Component : Symbol(Component, Decl(file.tsx, 10, 80))

};
77 changes: 77 additions & 0 deletions tests/baselines/reference/tsxGenericAttributesType1.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
=== tests/cases/conformance/jsx/file.tsx ===
import React = require('react');
>React : typeof React

const decorator = function <T>(Component: React.StatelessComponent<T>): React.StatelessComponent<T> {
>decorator : <T>(Component: React.StatelessComponent<T>) => React.StatelessComponent<T>
>function <T>(Component: React.StatelessComponent<T>): React.StatelessComponent<T> { return (props) => <Component {...props}></Component>} : <T>(Component: React.StatelessComponent<T>) => React.StatelessComponent<T>
>T : T
>Component : React.StatelessComponent<T>
>React : any
>StatelessComponent : React.StatelessComponent<P>
>T : T
>React : any
>StatelessComponent : React.StatelessComponent<P>
>T : T

return (props) => <Component {...props}></Component>
>(props) => <Component {...props}></Component> : (props: T & { children?: React.ReactNode; }) => JSX.Element
>props : T & { children?: React.ReactNode; }
><Component {...props}></Component> : JSX.Element
>Component : React.StatelessComponent<T>
>props : T & { children?: React.ReactNode; }
>Component : React.StatelessComponent<T>

};

const decorator2 = function <T extends { x: number }>(Component: React.StatelessComponent<T>): React.StatelessComponent<T> {
>decorator2 : <T extends { x: number; }>(Component: React.StatelessComponent<T>) => React.StatelessComponent<T>
>function <T extends { x: number }>(Component: React.StatelessComponent<T>): React.StatelessComponent<T> { return (props) => <Component {...props} x={2} ></Component>} : <T extends { x: number; }>(Component: React.StatelessComponent<T>) => React.StatelessComponent<T>
>T : T
>x : number
>Component : React.StatelessComponent<T>
>React : any
>StatelessComponent : React.StatelessComponent<P>
>T : T
>React : any
>StatelessComponent : React.StatelessComponent<P>
>T : T

return (props) => <Component {...props} x={2} ></Component>
>(props) => <Component {...props} x={2} ></Component> : (props: T & { children?: React.ReactNode; }) => JSX.Element
>props : T & { children?: React.ReactNode; }
><Component {...props} x={2} ></Component> : JSX.Element
>Component : React.StatelessComponent<T>
>props : T & { children?: React.ReactNode; }
>x : number
>2 : 2
>Component : React.StatelessComponent<T>

};

const decorator3 = function <T extends { x: number }, U extends { x: number } >(Component: React.StatelessComponent<T>): React.StatelessComponent<T> {
>decorator3 : <T extends { x: number; }, U extends { x: number; }>(Component: React.StatelessComponent<T>) => React.StatelessComponent<T>
>function <T extends { x: number }, U extends { x: number } >(Component: React.StatelessComponent<T>): React.StatelessComponent<T> { return (props) => <Component x={2} {...props} ></Component>} : <T extends { x: number; }, U extends { x: number; }>(Component: React.StatelessComponent<T>) => React.StatelessComponent<T>
>T : T
>x : number
>U : U
>x : number
>Component : React.StatelessComponent<T>
>React : any
>StatelessComponent : React.StatelessComponent<P>
>T : T
>React : any
>StatelessComponent : React.StatelessComponent<P>
>T : T

return (props) => <Component x={2} {...props} ></Component>
>(props) => <Component x={2} {...props} ></Component> : (props: T & { children?: React.ReactNode; }) => JSX.Element
>props : T & { children?: React.ReactNode; }
><Component x={2} {...props} ></Component> : JSX.Element
>Component : React.StatelessComponent<T>
>x : number
>2 : 2
>props : T & { children?: React.ReactNode; }
>Component : React.StatelessComponent<T>

};
11 changes: 11 additions & 0 deletions tests/baselines/reference/tsxGenericAttributesType2.errors.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
tests/cases/conformance/jsx/file.tsx(4,45): error TS2339: Property 'y' does not exist on type 'IntrinsicAttributes & { x: number; } & { children?: ReactNode; }'.


==== tests/cases/conformance/jsx/file.tsx (1 errors) ====
import React = require('react');

const decorator4 = function <T extends { x: number }>(Component: React.StatelessComponent<T>): React.StatelessComponent<T> {
return (props) => <Component {...props} y={"blah"} ></Component>
~~~~~~~~~~
!!! error TS2339: Property 'y' does not exist on type 'IntrinsicAttributes & { x: number; } & { children?: ReactNode; }'.
};
14 changes: 14 additions & 0 deletions tests/baselines/reference/tsxGenericAttributesType2.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//// [file.tsx]
import React = require('react');

const decorator4 = function <T extends { x: number }>(Component: React.StatelessComponent<T>): React.StatelessComponent<T> {
return (props) => <Component {...props} y={"blah"} ></Component>
};

//// [file.jsx]
"use strict";
exports.__esModule = true;
var React = require("react");
var decorator4 = function (Component) {
return function (props) { return <Component {...props} y={"blah"}></Component>; };
};
48 changes: 48 additions & 0 deletions tests/baselines/reference/tsxGenericAttributesType3.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
//// [file.tsx]
import React = require('react');

class B1<T extends { x: string } = { x:string } > extends React.Component<T, {}> {
render() {
return <div>hi</div>;
}
}
class B<U> extends React.Component<U, {}> {
render() {
return <B1 {...this.props} x="hi" />;
}
}

//// [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 B1 = (function (_super) {
__extends(B1, _super);
function B1() {
return _super !== null && _super.apply(this, arguments) || this;
}
B1.prototype.render = function () {
return <div>hi</div>;
};
return B1;
}(React.Component));
var B = (function (_super) {
__extends(B, _super);
function B() {
return _super !== null && _super.apply(this, arguments) || this;
}
B.prototype.render = function () {
return <B1 {...this.props} x="hi"/>;
};
return B;
}(React.Component));
41 changes: 41 additions & 0 deletions tests/baselines/reference/tsxGenericAttributesType3.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
=== tests/cases/conformance/jsx/file.tsx ===
import React = require('react');
>React : Symbol(React, Decl(file.tsx, 0, 0))

class B1<T extends { x: string } = { x:string } > extends React.Component<T, {}> {
>B1 : Symbol(B1, Decl(file.tsx, 0, 32))
>T : Symbol(T, Decl(file.tsx, 2, 9))
>x : Symbol(x, Decl(file.tsx, 2, 20))
>x : Symbol(x, Decl(file.tsx, 2, 36))
>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))
>T : Symbol(T, Decl(file.tsx, 2, 9))

render() {
>render : Symbol(B1.render, Decl(file.tsx, 2, 82))

return <div>hi</div>;
>div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2399, 45))
>div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2399, 45))
}
}
class B<U> extends React.Component<U, {}> {
>B : Symbol(B, Decl(file.tsx, 6, 1))
>U : Symbol(U, Decl(file.tsx, 7, 8))
>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))
>U : Symbol(U, Decl(file.tsx, 7, 8))

render() {
>render : Symbol(B.render, Decl(file.tsx, 7, 43))

return <B1 {...this.props} x="hi" />;
>B1 : Symbol(B1, Decl(file.tsx, 0, 32))
>this.props : Symbol(React.Component.props, Decl(react.d.ts, 166, 37))
>this : Symbol(B, Decl(file.tsx, 6, 1))
>props : Symbol(React.Component.props, Decl(react.d.ts, 166, 37))
>x : Symbol(x, Decl(file.tsx, 9, 34))
}
}
43 changes: 43 additions & 0 deletions tests/baselines/reference/tsxGenericAttributesType3.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
=== tests/cases/conformance/jsx/file.tsx ===
import React = require('react');
>React : typeof React

class B1<T extends { x: string } = { x:string } > extends React.Component<T, {}> {
>B1 : B1<T>
>T : T
>x : string
>x : string
>React.Component : React.Component<T, {}>
>React : typeof React
>Component : typeof React.Component
>T : T

render() {
>render : () => JSX.Element

return <div>hi</div>;
><div>hi</div> : JSX.Element
>div : any
>div : any
}
}
class B<U> extends React.Component<U, {}> {
>B : B<U>
>U : U
>React.Component : React.Component<U, {}>
>React : typeof React
>Component : typeof React.Component
>U : U

render() {
>render : () => JSX.Element

return <B1 {...this.props} x="hi" />;
><B1 {...this.props} x="hi" /> : JSX.Element
>B1 : typeof B1
>this.props : U & { children?: React.ReactNode; }
>this : this
>props : U & { children?: React.ReactNode; }
>x : string
}
}
19 changes: 19 additions & 0 deletions tests/baselines/reference/tsxGenericAttributesType4.errors.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
tests/cases/conformance/jsx/file.tsx(11,36): error TS2339: Property 'x' does not exist on type 'IntrinsicAttributes & IntrinsicClassAttributes<B1<{}>> & { children?: ReactNode; }'.


==== tests/cases/conformance/jsx/file.tsx (1 errors) ====
import React = require('react');

class B1<T extends { x: string }> extends React.Component<T, {}> {
render() {
return <div>hi</div>;
}
}
class B<U> extends React.Component<U, {}> {
render() {
// Should be an ok but as of 2.3.3 this will be an error as we will instantiate B1.props to be empty object
return <B1 {...this.props} x="hi" />;
~~~~~~
!!! error TS2339: Property 'x' does not exist on type 'IntrinsicAttributes & IntrinsicClassAttributes<B1<{}>> & { children?: ReactNode; }'.
}
}
Loading

0 comments on commit d68b436

Please sign in to comment.