-
Notifications
You must be signed in to change notification settings - Fork 13.2k
[Master] fix15742 #15789
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Master] fix15742 #15789
Changes from 5 commits
181ff86
bce7ddb
705771d
84f419b
8d09085
8907c70
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13548,6 +13548,20 @@ namespace ts { | |
| return _jsxElementChildrenPropertyName; | ||
| } | ||
|
|
||
| function getApparentTypeOfJsxPropsType(propsType: Type): Type { | ||
| if (propsType) { | ||
| if (propsType.flags & TypeFlags.Intersection) { | ||
| const propsApprentType: Type[] = []; | ||
|
||
| for (const t of (<UnionOrIntersectionType>propsType).types) { | ||
|
||
| propsApprentType.push(getApparentType(t)); | ||
| } | ||
| return getIntersectionType(propsApprentType); | ||
| } | ||
|
||
| return getApparentType(propsType); | ||
| } | ||
| return propsType; | ||
| } | ||
|
|
||
| /** | ||
| * Get JSX attributes type by trying to resolve openingLikeElement as a stateless function component. | ||
| * Return only attributes type of successfully resolved call signature. | ||
|
|
@@ -13568,6 +13582,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); | ||
|
|
@@ -13605,7 +13620,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) { | ||
|
|
||
| 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>; }; | ||
| }; |
| 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)) | ||
|
|
||
| }; |
| 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> | ||
|
|
||
| }; |
| 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; }'. | ||
| }; |
| 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>; }; | ||
| }; |
| 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)); |
| 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)) | ||
| } | ||
| } |
| 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 | ||
| } | ||
| } |
| 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; }'. | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like this better: