diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index d1dbc966952..14d5254e1e9 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7757,12 +7757,6 @@ namespace ts { let returnType = getUnionType(signatures.map(getReturnTypeOfSignature)); - // Issue an error if this return type isn't assignable to JSX.ElementClass - let elemClassType = getJsxGlobalElementClassType(); - if (elemClassType) { - checkTypeRelatedTo(returnType, elemClassType, assignableRelation, node, Diagnostics.JSX_element_type_0_is_not_a_constructor_function_for_JSX_elements); - } - return returnType; } @@ -7813,8 +7807,27 @@ namespace ts { let sym = getJsxElementTagSymbol(node); if (links.jsxFlags & JsxFlags.ClassElement) { + // Get the element instance type (the result of newing or invoking this tag) let elemInstanceType = getJsxElementInstanceType(node); + // Is this is a stateless function component? See if its single signature is + // assignable to the JSX Element Type with either 0 arguments, or 1 argument + // that is an object type + let callSignature = getSingleCallSignature(getTypeOfSymbol(sym)); + let callReturnType = callSignature && getReturnTypeOfSignature(callSignature); + let paramType = callSignature && (callSignature.parameters.length === 0 ? emptyObjectType : getTypeOfSymbol(callSignature.parameters[0])); + if (callReturnType && isTypeAssignableTo(callReturnType, jsxElementType) && paramType.flags & TypeFlags.ObjectType) { + // TODO: Things like 'ref' and 'key' are always valid, how to account for that? + return paramType; + } + + // Issue an error if this return type isn't assignable to JSX.ElementClass + let 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; } diff --git a/tests/baselines/reference/tsxStatelessFunctionComponents1.errors.txt b/tests/baselines/reference/tsxStatelessFunctionComponents1.errors.txt new file mode 100644 index 00000000000..343303f4b2c --- /dev/null +++ b/tests/baselines/reference/tsxStatelessFunctionComponents1.errors.txt @@ -0,0 +1,27 @@ +tests/cases/conformance/jsx/tsxStatelessFunctionComponents1.tsx(17,9): error TS2324: Property 'name' is missing in type '{ name: string; }'. +tests/cases/conformance/jsx/tsxStatelessFunctionComponents1.tsx(17,16): error TS2339: Property 'naaame' does not exist on type '{ name: string; }'. + + +==== tests/cases/conformance/jsx/tsxStatelessFunctionComponents1.tsx (2 errors) ==== + declare module JSX { + interface Element { el: any; } + interface IntrinsicElements { div: any; } + } + + + function Greet(x: {name: string}) { + return
Hello, {x}
; + } + function Meet({name = 'world'}) { + return
Hello, {x}
; + } + + // OK + let x = ; + // Error + let y = ; + ~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2324: Property 'name' is missing in type '{ name: string; }'. + ~~~~~~ +!!! error TS2339: Property 'naaame' does not exist on type '{ name: string; }'. + \ No newline at end of file diff --git a/tests/baselines/reference/tsxStatelessFunctionComponents1.js b/tests/baselines/reference/tsxStatelessFunctionComponents1.js new file mode 100644 index 00000000000..35a9f03644c --- /dev/null +++ b/tests/baselines/reference/tsxStatelessFunctionComponents1.js @@ -0,0 +1,32 @@ +//// [tsxStatelessFunctionComponents1.tsx] +declare module JSX { + interface Element { el: any; } + interface IntrinsicElements { div: any; } +} + + +function Greet(x: {name: string}) { + return
Hello, {x}
; +} +function Meet({name = 'world'}) { + return
Hello, {x}
; +} + +// OK +let x = ; +// Error +let y = ; + + +//// [tsxStatelessFunctionComponents1.jsx] +function Greet(x) { + return
Hello, {x}
; +} +function Meet(_a) { + var _b = _a.name, name = _b === void 0 ? 'world' : _b; + return
Hello, {x}
; +} +// OK +var x = ; +// Error +var y = ; diff --git a/tests/cases/conformance/jsx/tsxStatelessFunctionComponents1.tsx b/tests/cases/conformance/jsx/tsxStatelessFunctionComponents1.tsx new file mode 100644 index 00000000000..f2408632e7c --- /dev/null +++ b/tests/cases/conformance/jsx/tsxStatelessFunctionComponents1.tsx @@ -0,0 +1,19 @@ +//@filename: file.tsx +//@jsx: preserve +declare module JSX { + interface Element { el: any; } + interface IntrinsicElements { div: any; } +} + + +function Greet(x: {name: string}) { + return
Hello, {x}
; +} +function Meet({name = 'world'}) { + return
Hello, {x}
; +} + +// OK +let x = ; +// Error +let y = ;