Merge pull request #6358 from RyanCavanaugh/fix6349
Change logic in identifying JSX React SFCs
This commit is contained in:
commit
5f024a3c9f
9 changed files with 191 additions and 18 deletions
|
@ -8231,27 +8231,31 @@ namespace ts {
|
|||
// Get the element instance type (the result of newing or invoking this tag)
|
||||
const elemInstanceType = getJsxElementInstanceType(node);
|
||||
|
||||
// Is this is a stateless function component? See if its single signature is
|
||||
const elemClassType = getJsxGlobalElementClassType();
|
||||
|
||||
if (!elemClassType || !isTypeAssignableTo(elemInstanceType, elemClassType)) {
|
||||
// Is this is a stateless function component? See if its single signature's return type is
|
||||
// assignable to the JSX Element Type
|
||||
const callSignature = getSingleCallSignature(getTypeOfSymbol(sym));
|
||||
const elemType = getTypeOfSymbol(sym);
|
||||
const callSignatures = elemType && getSignaturesOfType(elemType, SignatureKind.Call);
|
||||
const callSignature = callSignatures && callSignatures.length > 0 && callSignatures[0];
|
||||
const callReturnType = callSignature && getReturnTypeOfSignature(callSignature);
|
||||
let paramType = callReturnType && (callSignature.parameters.length === 0 ? emptyObjectType : getTypeOfSymbol(callSignature.parameters[0]));
|
||||
if (callReturnType && isTypeAssignableTo(callReturnType, jsxElementType) && (paramType.flags & TypeFlags.ObjectType)) {
|
||||
if (callReturnType && isTypeAssignableTo(callReturnType, jsxElementType)) {
|
||||
// Intersect in JSX.IntrinsicAttributes if it exists
|
||||
const intrinsicAttributes = getJsxType(JsxNames.IntrinsicAttributes);
|
||||
if (intrinsicAttributes !== unknownType) {
|
||||
paramType = intersectTypes(intrinsicAttributes, paramType);
|
||||
}
|
||||
return paramType;
|
||||
return links.resolvedJsxType = paramType;
|
||||
}
|
||||
}
|
||||
|
||||
// Issue an error if this return type isn't assignable to JSX.ElementClass
|
||||
const elemClassType = getJsxGlobalElementClassType();
|
||||
if (elemClassType) {
|
||||
checkTypeRelatedTo(elemInstanceType, elemClassType, assignableRelation, node, Diagnostics.JSX_element_type_0_is_not_a_constructor_function_for_JSX_elements);
|
||||
}
|
||||
|
||||
|
||||
if (isTypeAny(elemInstanceType)) {
|
||||
return links.resolvedJsxType = elemInstanceType;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//// [file.tsx]
|
||||
declare module JSX {
|
||||
interface Element { }
|
||||
interface Element { something; }
|
||||
interface IntrinsicElements { }
|
||||
}
|
||||
|
||||
|
|
|
@ -2,11 +2,12 @@
|
|||
declare module JSX {
|
||||
>JSX : Symbol(JSX, Decl(file.tsx, 0, 0))
|
||||
|
||||
interface Element { }
|
||||
interface Element { something; }
|
||||
>Element : Symbol(Element, Decl(file.tsx, 0, 20))
|
||||
>something : Symbol(something, Decl(file.tsx, 1, 20))
|
||||
|
||||
interface IntrinsicElements { }
|
||||
>IntrinsicElements : Symbol(IntrinsicElements, Decl(file.tsx, 1, 22))
|
||||
>IntrinsicElements : Symbol(IntrinsicElements, Decl(file.tsx, 1, 33))
|
||||
}
|
||||
|
||||
interface Obj1 {
|
||||
|
|
|
@ -2,8 +2,9 @@
|
|||
declare module JSX {
|
||||
>JSX : any
|
||||
|
||||
interface Element { }
|
||||
interface Element { something; }
|
||||
>Element : Element
|
||||
>something : any
|
||||
|
||||
interface IntrinsicElements { }
|
||||
>IntrinsicElements : IntrinsicElements
|
||||
|
|
37
tests/baselines/reference/tsxStatelessFunctionComponents3.js
Normal file
37
tests/baselines/reference/tsxStatelessFunctionComponents3.js
Normal file
|
@ -0,0 +1,37 @@
|
|||
//// [file.tsx]
|
||||
|
||||
import React = require('react');
|
||||
|
||||
const Foo = (props: any) => <div/>;
|
||||
// Should be OK
|
||||
const foo = <Foo />;
|
||||
|
||||
|
||||
// Should be OK
|
||||
var MainMenu: React.StatelessComponent<{}> = (props) => (<div>
|
||||
<h3>Main Menu</h3>
|
||||
</div>);
|
||||
|
||||
var App: React.StatelessComponent<{ children }> = ({children}) => (
|
||||
<div >
|
||||
<MainMenu/>
|
||||
</div>
|
||||
);
|
||||
|
||||
//// [file.jsx]
|
||||
define(["require", "exports", 'react'], function (require, exports, React) {
|
||||
"use strict";
|
||||
var Foo = function (props) { return <div />; };
|
||||
// Should be OK
|
||||
var foo = <Foo />;
|
||||
// Should be OK
|
||||
var MainMenu = function (props) { return (<div>
|
||||
<h3>Main Menu</h3>
|
||||
</div>); };
|
||||
var App = function (_a) {
|
||||
var children = _a.children;
|
||||
return (<div>
|
||||
<MainMenu />
|
||||
</div>);
|
||||
};
|
||||
});
|
|
@ -0,0 +1,48 @@
|
|||
=== tests/cases/conformance/jsx/file.tsx ===
|
||||
|
||||
import React = require('react');
|
||||
>React : Symbol(React, Decl(file.tsx, 0, 0))
|
||||
|
||||
const Foo = (props: any) => <div/>;
|
||||
>Foo : Symbol(Foo, Decl(file.tsx, 3, 5))
|
||||
>props : Symbol(props, Decl(file.tsx, 3, 13))
|
||||
>div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 927, 45))
|
||||
|
||||
// Should be OK
|
||||
const foo = <Foo />;
|
||||
>foo : Symbol(foo, Decl(file.tsx, 5, 5))
|
||||
>Foo : Symbol(Foo, Decl(file.tsx, 3, 5))
|
||||
|
||||
|
||||
// Should be OK
|
||||
var MainMenu: React.StatelessComponent<{}> = (props) => (<div>
|
||||
>MainMenu : Symbol(MainMenu, Decl(file.tsx, 9, 3))
|
||||
>React : Symbol(React, Decl(file.tsx, 0, 0))
|
||||
>StatelessComponent : Symbol(React.StatelessComponent, Decl(react.d.ts, 139, 5))
|
||||
>props : Symbol(props, Decl(file.tsx, 9, 46))
|
||||
>div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 927, 45))
|
||||
|
||||
<h3>Main Menu</h3>
|
||||
>h3 : Symbol(JSX.IntrinsicElements.h3, Decl(react.d.ts, 939, 48))
|
||||
>h3 : Symbol(JSX.IntrinsicElements.h3, Decl(react.d.ts, 939, 48))
|
||||
|
||||
</div>);
|
||||
>div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 927, 45))
|
||||
|
||||
var App: React.StatelessComponent<{ children }> = ({children}) => (
|
||||
>App : Symbol(App, Decl(file.tsx, 13, 3))
|
||||
>React : Symbol(React, Decl(file.tsx, 0, 0))
|
||||
>StatelessComponent : Symbol(React.StatelessComponent, Decl(react.d.ts, 139, 5))
|
||||
>children : Symbol(children, Decl(file.tsx, 13, 35))
|
||||
>children : Symbol(children, Decl(file.tsx, 13, 52))
|
||||
|
||||
<div >
|
||||
>div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 927, 45))
|
||||
|
||||
<MainMenu/>
|
||||
>MainMenu : Symbol(MainMenu, Decl(file.tsx, 9, 3))
|
||||
|
||||
</div>
|
||||
>div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 927, 45))
|
||||
|
||||
);
|
|
@ -0,0 +1,59 @@
|
|||
=== tests/cases/conformance/jsx/file.tsx ===
|
||||
|
||||
import React = require('react');
|
||||
>React : typeof React
|
||||
|
||||
const Foo = (props: any) => <div/>;
|
||||
>Foo : (props: any) => JSX.Element
|
||||
>(props: any) => <div/> : (props: any) => JSX.Element
|
||||
>props : any
|
||||
><div/> : JSX.Element
|
||||
>div : any
|
||||
|
||||
// Should be OK
|
||||
const foo = <Foo />;
|
||||
>foo : JSX.Element
|
||||
><Foo /> : JSX.Element
|
||||
>Foo : (props: any) => JSX.Element
|
||||
|
||||
|
||||
// Should be OK
|
||||
var MainMenu: React.StatelessComponent<{}> = (props) => (<div>
|
||||
>MainMenu : React.StatelessComponent<{}>
|
||||
>React : any
|
||||
>StatelessComponent : React.StatelessComponent<P>
|
||||
>(props) => (<div> <h3>Main Menu</h3></div>) : (props: {}) => JSX.Element
|
||||
>props : {}
|
||||
>(<div> <h3>Main Menu</h3></div>) : JSX.Element
|
||||
><div> <h3>Main Menu</h3></div> : JSX.Element
|
||||
>div : any
|
||||
|
||||
<h3>Main Menu</h3>
|
||||
><h3>Main Menu</h3> : JSX.Element
|
||||
>h3 : any
|
||||
>h3 : any
|
||||
|
||||
</div>);
|
||||
>div : any
|
||||
|
||||
var App: React.StatelessComponent<{ children }> = ({children}) => (
|
||||
>App : React.StatelessComponent<{ children: any; }>
|
||||
>React : any
|
||||
>StatelessComponent : React.StatelessComponent<P>
|
||||
>children : any
|
||||
>({children}) => ( <div > <MainMenu/> </div>) : ({children}: { children: any; }) => JSX.Element
|
||||
>children : any
|
||||
>( <div > <MainMenu/> </div>) : JSX.Element
|
||||
|
||||
<div >
|
||||
><div > <MainMenu/> </div> : JSX.Element
|
||||
>div : any
|
||||
|
||||
<MainMenu/>
|
||||
><MainMenu/> : JSX.Element
|
||||
>MainMenu : React.StatelessComponent<{}>
|
||||
|
||||
</div>
|
||||
>div : any
|
||||
|
||||
);
|
|
@ -1,7 +1,7 @@
|
|||
//@filename: file.tsx
|
||||
//@jsx: preserve
|
||||
declare module JSX {
|
||||
interface Element { }
|
||||
interface Element { something; }
|
||||
interface IntrinsicElements { }
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
// @filename: file.tsx
|
||||
// @jsx: preserve
|
||||
// @module: amd
|
||||
// @noLib: true
|
||||
// @libFiles: react.d.ts,lib.d.ts
|
||||
|
||||
import React = require('react');
|
||||
|
||||
const Foo = (props: any) => <div/>;
|
||||
// Should be OK
|
||||
const foo = <Foo />;
|
||||
|
||||
|
||||
// Should be OK
|
||||
var MainMenu: React.StatelessComponent<{}> = (props) => (<div>
|
||||
<h3>Main Menu</h3>
|
||||
</div>);
|
||||
|
||||
var App: React.StatelessComponent<{ children }> = ({children}) => (
|
||||
<div >
|
||||
<MainMenu/>
|
||||
</div>
|
||||
);
|
Loading…
Reference in a new issue