Improve error message for invalid return type of JSX component (#32702)

* New diagnostic message for wrong JSX function component

* Component and Mixed type

* fix existing tests

* add new test for JSX component return type error

* fix tslint error

* update diagnostic message to include component name

* accept baseline

* update tests

* missing semicolon

* accept baseline

Co-authored-by: Wesley Wigham <wwigham@gmail.com>
This commit is contained in:
uhyo 2020-03-31 05:04:33 +09:00 committed by GitHub
parent 4c440e5e5b
commit 1f56ab02f0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 509 additions and 47 deletions

View file

@ -23356,18 +23356,18 @@ namespace ts {
return anyType;
}
function checkJsxReturnAssignableToAppropriateBound(refKind: JsxReferenceKind, elemInstanceType: Type, openingLikeElement: Node) {
function checkJsxReturnAssignableToAppropriateBound(refKind: JsxReferenceKind, elemInstanceType: Type, openingLikeElement: JsxOpeningLikeElement) {
if (refKind === JsxReferenceKind.Function) {
const sfcReturnConstraint = getJsxStatelessElementTypeAt(openingLikeElement);
if (sfcReturnConstraint) {
checkTypeRelatedTo(elemInstanceType, sfcReturnConstraint, assignableRelation, openingLikeElement, Diagnostics.JSX_element_type_0_is_not_a_constructor_function_for_JSX_elements);
checkTypeRelatedTo(elemInstanceType, sfcReturnConstraint, assignableRelation, openingLikeElement.tagName, Diagnostics.Its_return_type_0_is_not_a_valid_JSX_element, generateInitialErrorChain);
}
}
else if (refKind === JsxReferenceKind.Component) {
const classConstraint = getJsxElementClassTypeAt(openingLikeElement);
if (classConstraint) {
// Issue an error if this return type isn't assignable to JSX.ElementClass or JSX.Element, failing that
checkTypeRelatedTo(elemInstanceType, classConstraint, assignableRelation, openingLikeElement, Diagnostics.JSX_element_type_0_is_not_a_constructor_function_for_JSX_elements);
// Issue an error if this return type isn't assignable to JSX.ElementClass, failing that
checkTypeRelatedTo(elemInstanceType, classConstraint, assignableRelation, openingLikeElement.tagName, Diagnostics.Its_instance_type_0_is_not_a_valid_JSX_element, generateInitialErrorChain);
}
}
else { // Mixed
@ -23377,7 +23377,12 @@ namespace ts {
return;
}
const combined = getUnionType([sfcReturnConstraint, classConstraint]);
checkTypeRelatedTo(elemInstanceType, combined, assignableRelation, openingLikeElement, Diagnostics.JSX_element_type_0_is_not_a_constructor_function_for_JSX_elements);
checkTypeRelatedTo(elemInstanceType, combined, assignableRelation, openingLikeElement.tagName, Diagnostics.Its_element_type_0_is_not_a_valid_JSX_element, generateInitialErrorChain);
}
function generateInitialErrorChain(): DiagnosticMessageChain {
const componentName = getTextOfNode(openingLikeElement.tagName);
return chainDiagnosticMessages(/* details */ undefined, Diagnostics._0_cannot_be_used_as_a_JSX_component, componentName);
}
}
@ -23468,8 +23473,9 @@ namespace ts {
}
if (isNodeOpeningLikeElement) {
const sig = getResolvedSignature(node as JsxOpeningLikeElement);
checkJsxReturnAssignableToAppropriateBound(getJsxReferenceKind(node as JsxOpeningLikeElement), getReturnTypeOfSignature(sig), node);
const jsxOpeningLikeNode = node as JsxOpeningLikeElement;
const sig = getResolvedSignature(jsxOpeningLikeNode);
checkJsxReturnAssignableToAppropriateBound(getJsxReferenceKind(jsxOpeningLikeNode), getReturnTypeOfSignature(sig), jsxOpeningLikeNode);
}
}

View file

@ -2947,6 +2947,22 @@
"category": "Error",
"code": 2785
},
"'{0}' cannot be used as a JSX component.": {
"category": "Error",
"code": 2786
},
"Its return type '{0}' is not a valid JSX element.": {
"category": "Error",
"code": 2787
},
"Its instance type '{0}' is not a valid JSX element.": {
"category": "Error",
"code": 2788
},
"Its element type '{0}' is not a valid JSX element.": {
"category": "Error",
"code": 2789
},
"Import declaration '{0}' is using private name '{1}'.": {
"category": "Error",

View file

@ -1,11 +1,14 @@
tests/cases/conformance/jsx/inline/index.tsx(5,1): error TS2741: Property '__predomBrand' is missing in type 'import("tests/cases/conformance/jsx/inline/renderer").dom.JSX.Element' but required in type 'import("tests/cases/conformance/jsx/inline/renderer2").predom.JSX.Element'.
tests/cases/conformance/jsx/inline/index.tsx(21,21): error TS2605: JSX element type 'import("tests/cases/conformance/jsx/inline/renderer2").predom.JSX.Element' is not a constructor function for JSX elements.
Property '__domBrand' is missing in type 'import("tests/cases/conformance/jsx/inline/renderer2").predom.JSX.Element' but required in type 'import("tests/cases/conformance/jsx/inline/renderer").dom.JSX.Element'.
tests/cases/conformance/jsx/inline/index.tsx(21,22): error TS2786: 'MySFC' cannot be used as a JSX component.
Its return type 'import("tests/cases/conformance/jsx/inline/renderer2").predom.JSX.Element' is not a valid JSX element.
Property '__domBrand' is missing in type 'import("tests/cases/conformance/jsx/inline/renderer2").predom.JSX.Element' but required in type 'import("tests/cases/conformance/jsx/inline/renderer").dom.JSX.Element'.
tests/cases/conformance/jsx/inline/index.tsx(21,40): error TS2322: Type 'import("tests/cases/conformance/jsx/inline/renderer").dom.JSX.Element' is not assignable to type 'import("tests/cases/conformance/jsx/inline/renderer2").predom.JSX.Element'.
tests/cases/conformance/jsx/inline/index.tsx(21,40): error TS2605: JSX element type 'MyClass' is not a constructor function for JSX elements.
Property '__domBrand' is missing in type 'MyClass' but required in type 'ElementClass'.
tests/cases/conformance/jsx/inline/index.tsx(21,41): error TS2786: 'MyClass' cannot be used as a JSX component.
Its instance type 'MyClass' is not a valid JSX element.
Property '__domBrand' is missing in type 'MyClass' but required in type 'ElementClass'.
tests/cases/conformance/jsx/inline/index.tsx(21,63): error TS2322: Type 'import("tests/cases/conformance/jsx/inline/renderer").dom.JSX.Element' is not assignable to type 'import("tests/cases/conformance/jsx/inline/renderer2").predom.JSX.Element'.
tests/cases/conformance/jsx/inline/index.tsx(21,63): error TS2605: JSX element type 'MyClass' is not a constructor function for JSX elements.
tests/cases/conformance/jsx/inline/index.tsx(21,64): error TS2786: 'MyClass' cannot be used as a JSX component.
Its instance type 'MyClass' is not a valid JSX element.
tests/cases/conformance/jsx/inline/index.tsx(24,42): error TS2322: Type 'import("tests/cases/conformance/jsx/inline/renderer2").predom.JSX.Element' is not assignable to type 'import("tests/cases/conformance/jsx/inline/renderer").dom.JSX.Element'.
tests/cases/conformance/jsx/inline/index.tsx(24,48): error TS2322: Type 'import("tests/cases/conformance/jsx/inline/renderer2").predom.JSX.Element' is not assignable to type 'import("tests/cases/conformance/jsx/inline/renderer").dom.JSX.Element'.
@ -95,20 +98,23 @@ tests/cases/conformance/jsx/inline/index.tsx(24,48): error TS2322: Type 'import(
// Should fail, no dom elements
const _brokenTree = <MySFC x={1} y={2}><MyClass x={3} y={4} /><MyClass x={5} y={6} /></MySFC>
~~~~~~~~~~~~~~~~~~~
!!! error TS2605: JSX element type 'import("tests/cases/conformance/jsx/inline/renderer2").predom.JSX.Element' is not a constructor function for JSX elements.
!!! error TS2605: Property '__domBrand' is missing in type 'import("tests/cases/conformance/jsx/inline/renderer2").predom.JSX.Element' but required in type 'import("tests/cases/conformance/jsx/inline/renderer").dom.JSX.Element'.
~~~~~
!!! error TS2786: 'MySFC' cannot be used as a JSX component.
!!! error TS2786: Its return type 'import("tests/cases/conformance/jsx/inline/renderer2").predom.JSX.Element' is not a valid JSX element.
!!! error TS2786: Property '__domBrand' is missing in type 'import("tests/cases/conformance/jsx/inline/renderer2").predom.JSX.Element' but required in type 'import("tests/cases/conformance/jsx/inline/renderer").dom.JSX.Element'.
!!! related TS2728 tests/cases/conformance/jsx/inline/renderer.d.ts:7:13: '__domBrand' is declared here.
~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2322: Type 'import("tests/cases/conformance/jsx/inline/renderer").dom.JSX.Element' is not assignable to type 'import("tests/cases/conformance/jsx/inline/renderer2").predom.JSX.Element'.
~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2605: JSX element type 'MyClass' is not a constructor function for JSX elements.
!!! error TS2605: Property '__domBrand' is missing in type 'MyClass' but required in type 'ElementClass'.
~~~~~~~
!!! error TS2786: 'MyClass' cannot be used as a JSX component.
!!! error TS2786: Its instance type 'MyClass' is not a valid JSX element.
!!! error TS2786: Property '__domBrand' is missing in type 'MyClass' but required in type 'ElementClass'.
!!! related TS2728 tests/cases/conformance/jsx/inline/renderer.d.ts:7:13: '__domBrand' is declared here.
~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2322: Type 'import("tests/cases/conformance/jsx/inline/renderer").dom.JSX.Element' is not assignable to type 'import("tests/cases/conformance/jsx/inline/renderer2").predom.JSX.Element'.
~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2605: JSX element type 'MyClass' is not a constructor function for JSX elements.
~~~~~~~
!!! error TS2786: 'MyClass' cannot be used as a JSX component.
!!! error TS2786: Its instance type 'MyClass' is not a valid JSX element.
// Should fail, nondom isn't allowed as children of dom
const _brokenTree2 = <DOMSFC x={1} y={2}>{tree}{tree}</DOMSFC>

View file

@ -0,0 +1,103 @@
tests/cases/compiler/jsxComponentTypeErrors.tsx(16,11): error TS2786: 'this' cannot be used as a JSX component.
Its return type '{ type: "foo" | undefined; }' is not a valid JSX element.
Types of property 'type' are incompatible.
Type '"foo" | undefined' is not assignable to type '"element"'.
Type 'undefined' is not assignable to type '"element"'.
tests/cases/compiler/jsxComponentTypeErrors.tsx(25,16): error TS2786: 'FunctionComponent' cannot be used as a JSX component.
Its return type '{ type: "abc" | undefined; }' is not a valid JSX element.
Types of property 'type' are incompatible.
Type '"abc" | undefined' is not assignable to type '"element"'.
Type 'undefined' is not assignable to type '"element"'.
tests/cases/compiler/jsxComponentTypeErrors.tsx(26,16): error TS2786: 'FunctionComponent' cannot be used as a JSX component.
Its return type '{ type: "abc" | undefined; }' is not a valid JSX element.
tests/cases/compiler/jsxComponentTypeErrors.tsx(27,16): error TS2786: 'ClassComponent' cannot be used as a JSX component.
Its instance type 'ClassComponent' is not a valid JSX element.
Types of property 'type' are incompatible.
Type 'string' is not assignable to type '"element-class"'.
tests/cases/compiler/jsxComponentTypeErrors.tsx(28,16): error TS2786: 'MixedComponent' cannot be used as a JSX component.
Its element type 'ClassComponent | { type: string | undefined; }' is not a valid JSX element.
Type 'ClassComponent' is not assignable to type 'Element | ElementClass | null'.
Type 'ClassComponent' is not assignable to type 'ElementClass'.
tests/cases/compiler/jsxComponentTypeErrors.tsx(37,16): error TS2786: 'obj.MemberFunctionComponent' cannot be used as a JSX component.
Its return type '{}' is not a valid JSX element.
Property 'type' is missing in type '{}' but required in type 'Element'.
tests/cases/compiler/jsxComponentTypeErrors.tsx(38,16): error TS2786: 'obj. MemberClassComponent' cannot be used as a JSX component.
Its instance type 'MemberClassComponent' is not a valid JSX element.
Property 'type' is missing in type 'MemberClassComponent' but required in type 'ElementClass'.
==== tests/cases/compiler/jsxComponentTypeErrors.tsx (7 errors) ====
namespace JSX {
export interface Element {
type: 'element';
}
export interface ElementClass {
type: 'element-class';
}
}
function FunctionComponent<T extends string>({type}: {type?: T}) {
return {
type
}
}
FunctionComponent.useThis = function() {
return <this type="foo" />;
~~~~
!!! error TS2786: 'this' cannot be used as a JSX component.
!!! error TS2786: Its return type '{ type: "foo" | undefined; }' is not a valid JSX element.
!!! error TS2786: Types of property 'type' are incompatible.
!!! error TS2786: Type '"foo" | undefined' is not assignable to type '"element"'.
!!! error TS2786: Type 'undefined' is not assignable to type '"element"'.
}
class ClassComponent {
type = 'string';
}
const MixedComponent = Math.random() ? FunctionComponent : ClassComponent;
const elem1 = <FunctionComponent type="abc" />;
~~~~~~~~~~~~~~~~~
!!! error TS2786: 'FunctionComponent' cannot be used as a JSX component.
!!! error TS2786: Its return type '{ type: "abc" | undefined; }' is not a valid JSX element.
!!! error TS2786: Types of property 'type' are incompatible.
!!! error TS2786: Type '"abc" | undefined' is not assignable to type '"element"'.
!!! error TS2786: Type 'undefined' is not assignable to type '"element"'.
const elem2 = <FunctionComponent<"abc"> />;
~~~~~~~~~~~~~~~~~
!!! error TS2786: 'FunctionComponent' cannot be used as a JSX component.
!!! error TS2786: Its return type '{ type: "abc" | undefined; }' is not a valid JSX element.
const elem3 = <ClassComponent />;
~~~~~~~~~~~~~~
!!! error TS2786: 'ClassComponent' cannot be used as a JSX component.
!!! error TS2786: Its instance type 'ClassComponent' is not a valid JSX element.
!!! error TS2786: Types of property 'type' are incompatible.
!!! error TS2786: Type 'string' is not assignable to type '"element-class"'.
const elem4 = <MixedComponent />;
~~~~~~~~~~~~~~
!!! error TS2786: 'MixedComponent' cannot be used as a JSX component.
!!! error TS2786: Its element type 'ClassComponent | { type: string | undefined; }' is not a valid JSX element.
!!! error TS2786: Type 'ClassComponent' is not assignable to type 'Element | ElementClass | null'.
!!! error TS2786: Type 'ClassComponent' is not assignable to type 'ElementClass'.
const obj = {
MemberFunctionComponent() {
return {};
},
MemberClassComponent: class {},
};
const elem5 = <obj.MemberFunctionComponent />;
~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2786: 'obj.MemberFunctionComponent' cannot be used as a JSX component.
!!! error TS2786: Its return type '{}' is not a valid JSX element.
!!! error TS2786: Property 'type' is missing in type '{}' but required in type 'Element'.
!!! related TS2728 tests/cases/compiler/jsxComponentTypeErrors.tsx:3:5: 'type' is declared here.
const elem6 = <obj. MemberClassComponent />;
~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2786: 'obj. MemberClassComponent' cannot be used as a JSX component.
!!! error TS2786: Its instance type 'MemberClassComponent' is not a valid JSX element.
!!! error TS2786: Property 'type' is missing in type 'MemberClassComponent' but required in type 'ElementClass'.
!!! related TS2728 tests/cases/compiler/jsxComponentTypeErrors.tsx:6:5: 'type' is declared here.

View file

@ -0,0 +1,75 @@
//// [jsxComponentTypeErrors.tsx]
namespace JSX {
export interface Element {
type: 'element';
}
export interface ElementClass {
type: 'element-class';
}
}
function FunctionComponent<T extends string>({type}: {type?: T}) {
return {
type
}
}
FunctionComponent.useThis = function() {
return <this type="foo" />;
}
class ClassComponent {
type = 'string';
}
const MixedComponent = Math.random() ? FunctionComponent : ClassComponent;
const elem1 = <FunctionComponent type="abc" />;
const elem2 = <FunctionComponent<"abc"> />;
const elem3 = <ClassComponent />;
const elem4 = <MixedComponent />;
const obj = {
MemberFunctionComponent() {
return {};
},
MemberClassComponent: class {},
};
const elem5 = <obj.MemberFunctionComponent />;
const elem6 = <obj. MemberClassComponent />;
//// [jsxComponentTypeErrors.jsx]
"use strict";
function FunctionComponent(_a) {
var type = _a.type;
return {
type: type
};
}
FunctionComponent.useThis = function () {
return <this type="foo"/>;
};
var ClassComponent = /** @class */ (function () {
function ClassComponent() {
this.type = 'string';
}
return ClassComponent;
}());
var MixedComponent = Math.random() ? FunctionComponent : ClassComponent;
var elem1 = <FunctionComponent type="abc"/>;
var elem2 = <FunctionComponent />;
var elem3 = <ClassComponent />;
var elem4 = <MixedComponent />;
var obj = {
MemberFunctionComponent: function () {
return {};
},
MemberClassComponent: /** @class */ (function () {
function MemberClassComponent() {
}
return MemberClassComponent;
}())
};
var elem5 = <obj.MemberFunctionComponent />;
var elem6 = <obj.MemberClassComponent />;

View file

@ -0,0 +1,97 @@
=== tests/cases/compiler/jsxComponentTypeErrors.tsx ===
namespace JSX {
>JSX : Symbol(JSX, Decl(jsxComponentTypeErrors.tsx, 0, 0))
export interface Element {
>Element : Symbol(Element, Decl(jsxComponentTypeErrors.tsx, 0, 15))
type: 'element';
>type : Symbol(Element.type, Decl(jsxComponentTypeErrors.tsx, 1, 28))
}
export interface ElementClass {
>ElementClass : Symbol(ElementClass, Decl(jsxComponentTypeErrors.tsx, 3, 3))
type: 'element-class';
>type : Symbol(ElementClass.type, Decl(jsxComponentTypeErrors.tsx, 4, 33))
}
}
function FunctionComponent<T extends string>({type}: {type?: T}) {
>FunctionComponent : Symbol(FunctionComponent, Decl(jsxComponentTypeErrors.tsx, 7, 1), Decl(jsxComponentTypeErrors.tsx, 13, 1))
>T : Symbol(T, Decl(jsxComponentTypeErrors.tsx, 9, 27))
>type : Symbol(type, Decl(jsxComponentTypeErrors.tsx, 9, 46))
>type : Symbol(type, Decl(jsxComponentTypeErrors.tsx, 9, 54))
>T : Symbol(T, Decl(jsxComponentTypeErrors.tsx, 9, 27))
return {
type
>type : Symbol(type, Decl(jsxComponentTypeErrors.tsx, 10, 10))
}
}
FunctionComponent.useThis = function() {
>FunctionComponent.useThis : Symbol(FunctionComponent.useThis, Decl(jsxComponentTypeErrors.tsx, 13, 1))
>FunctionComponent : Symbol(FunctionComponent, Decl(jsxComponentTypeErrors.tsx, 7, 1), Decl(jsxComponentTypeErrors.tsx, 13, 1))
>useThis : Symbol(FunctionComponent.useThis, Decl(jsxComponentTypeErrors.tsx, 13, 1))
return <this type="foo" />;
>this : Symbol(FunctionComponent, Decl(jsxComponentTypeErrors.tsx, 7, 1), Decl(jsxComponentTypeErrors.tsx, 13, 1))
>type : Symbol(type, Decl(jsxComponentTypeErrors.tsx, 15, 14))
}
class ClassComponent {
>ClassComponent : Symbol(ClassComponent, Decl(jsxComponentTypeErrors.tsx, 16, 1))
type = 'string';
>type : Symbol(ClassComponent.type, Decl(jsxComponentTypeErrors.tsx, 18, 22))
}
const MixedComponent = Math.random() ? FunctionComponent : ClassComponent;
>MixedComponent : Symbol(MixedComponent, Decl(jsxComponentTypeErrors.tsx, 22, 5))
>Math.random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --))
>Math : Symbol(Math, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --))
>FunctionComponent : Symbol(FunctionComponent, Decl(jsxComponentTypeErrors.tsx, 7, 1), Decl(jsxComponentTypeErrors.tsx, 13, 1))
>ClassComponent : Symbol(ClassComponent, Decl(jsxComponentTypeErrors.tsx, 16, 1))
const elem1 = <FunctionComponent type="abc" />;
>elem1 : Symbol(elem1, Decl(jsxComponentTypeErrors.tsx, 24, 5))
>FunctionComponent : Symbol(FunctionComponent, Decl(jsxComponentTypeErrors.tsx, 7, 1), Decl(jsxComponentTypeErrors.tsx, 13, 1))
>type : Symbol(type, Decl(jsxComponentTypeErrors.tsx, 24, 32))
const elem2 = <FunctionComponent<"abc"> />;
>elem2 : Symbol(elem2, Decl(jsxComponentTypeErrors.tsx, 25, 5))
>FunctionComponent : Symbol(FunctionComponent, Decl(jsxComponentTypeErrors.tsx, 7, 1), Decl(jsxComponentTypeErrors.tsx, 13, 1))
const elem3 = <ClassComponent />;
>elem3 : Symbol(elem3, Decl(jsxComponentTypeErrors.tsx, 26, 5))
>ClassComponent : Symbol(ClassComponent, Decl(jsxComponentTypeErrors.tsx, 16, 1))
const elem4 = <MixedComponent />;
>elem4 : Symbol(elem4, Decl(jsxComponentTypeErrors.tsx, 27, 5))
>MixedComponent : Symbol(MixedComponent, Decl(jsxComponentTypeErrors.tsx, 22, 5))
const obj = {
>obj : Symbol(obj, Decl(jsxComponentTypeErrors.tsx, 29, 5))
MemberFunctionComponent() {
>MemberFunctionComponent : Symbol(MemberFunctionComponent, Decl(jsxComponentTypeErrors.tsx, 29, 13))
return {};
},
MemberClassComponent: class {},
>MemberClassComponent : Symbol(MemberClassComponent, Decl(jsxComponentTypeErrors.tsx, 32, 4))
};
const elem5 = <obj.MemberFunctionComponent />;
>elem5 : Symbol(elem5, Decl(jsxComponentTypeErrors.tsx, 36, 5))
>obj.MemberFunctionComponent : Symbol(MemberFunctionComponent, Decl(jsxComponentTypeErrors.tsx, 29, 13))
>obj : Symbol(obj, Decl(jsxComponentTypeErrors.tsx, 29, 5))
>MemberFunctionComponent : Symbol(MemberFunctionComponent, Decl(jsxComponentTypeErrors.tsx, 29, 13))
const elem6 = <obj. MemberClassComponent />;
>elem6 : Symbol(elem6, Decl(jsxComponentTypeErrors.tsx, 37, 5))
>obj. MemberClassComponent : Symbol(MemberClassComponent, Decl(jsxComponentTypeErrors.tsx, 32, 4))
>obj : Symbol(obj, Decl(jsxComponentTypeErrors.tsx, 29, 5))
>MemberClassComponent : Symbol(MemberClassComponent, Decl(jsxComponentTypeErrors.tsx, 32, 4))

View file

@ -0,0 +1,107 @@
=== tests/cases/compiler/jsxComponentTypeErrors.tsx ===
namespace JSX {
export interface Element {
type: 'element';
>type : "element"
}
export interface ElementClass {
type: 'element-class';
>type : "element-class"
}
}
function FunctionComponent<T extends string>({type}: {type?: T}) {
>FunctionComponent : typeof FunctionComponent
>type : T | undefined
>type : T | undefined
return {
>{ type } : { type: T | undefined; }
type
>type : T | undefined
}
}
FunctionComponent.useThis = function() {
>FunctionComponent.useThis = function() { return <this type="foo" />;} : () => JSX.Element
>FunctionComponent.useThis : () => JSX.Element
>FunctionComponent : typeof FunctionComponent
>useThis : () => JSX.Element
>function() { return <this type="foo" />;} : () => JSX.Element
return <this type="foo" />;
><this type="foo" /> : JSX.Element
>this : typeof FunctionComponent
>type : "foo"
}
class ClassComponent {
>ClassComponent : ClassComponent
type = 'string';
>type : string
>'string' : "string"
}
const MixedComponent = Math.random() ? FunctionComponent : ClassComponent;
>MixedComponent : typeof FunctionComponent | typeof ClassComponent
>Math.random() ? FunctionComponent : ClassComponent : typeof FunctionComponent | typeof ClassComponent
>Math.random() : number
>Math.random : () => number
>Math : Math
>random : () => number
>FunctionComponent : typeof FunctionComponent
>ClassComponent : typeof ClassComponent
const elem1 = <FunctionComponent type="abc" />;
>elem1 : JSX.Element
><FunctionComponent type="abc" /> : JSX.Element
>FunctionComponent : typeof FunctionComponent
>type : "abc"
const elem2 = <FunctionComponent<"abc"> />;
>elem2 : JSX.Element
><FunctionComponent<"abc"> /> : JSX.Element
>FunctionComponent : typeof FunctionComponent
const elem3 = <ClassComponent />;
>elem3 : JSX.Element
><ClassComponent /> : JSX.Element
>ClassComponent : typeof ClassComponent
const elem4 = <MixedComponent />;
>elem4 : JSX.Element
><MixedComponent /> : JSX.Element
>MixedComponent : typeof FunctionComponent | typeof ClassComponent
const obj = {
>obj : { MemberFunctionComponent(): {}; MemberClassComponent: typeof MemberClassComponent; }
>{ MemberFunctionComponent() { return {}; }, MemberClassComponent: class {},} : { MemberFunctionComponent(): {}; MemberClassComponent: typeof MemberClassComponent; }
MemberFunctionComponent() {
>MemberFunctionComponent : () => {}
return {};
>{} : {}
},
MemberClassComponent: class {},
>MemberClassComponent : typeof MemberClassComponent
>class {} : typeof MemberClassComponent
};
const elem5 = <obj.MemberFunctionComponent />;
>elem5 : JSX.Element
><obj.MemberFunctionComponent /> : JSX.Element
>obj.MemberFunctionComponent : () => {}
>obj : { MemberFunctionComponent(): {}; MemberClassComponent: typeof MemberClassComponent; }
>MemberFunctionComponent : () => {}
const elem6 = <obj. MemberClassComponent />;
>elem6 : JSX.Element
><obj. MemberClassComponent /> : JSX.Element
>obj. MemberClassComponent : typeof MemberClassComponent
>obj : { MemberFunctionComponent(): {}; MemberClassComponent: typeof MemberClassComponent; }
>MemberClassComponent : typeof MemberClassComponent

View file

@ -1,6 +1,7 @@
tests/cases/conformance/jsx/file.tsx(13,1): error TS2605: JSX element type '{ x: number; }' is not a constructor function for JSX elements.
Property 'render' is missing in type '{ x: number; }' but required in type 'ElementClass'.
tests/cases/conformance/jsx/file.tsx(13,2): error TS2322: Type '{ x: number; }' is not assignable to type 'string'.
tests/cases/conformance/jsx/file.tsx(13,2): error TS2786: 'Obj1' cannot be used as a JSX component.
Its instance type '{ x: number; }' is not a valid JSX element.
Property 'render' is missing in type '{ x: number; }' but required in type 'ElementClass'.
tests/cases/conformance/jsx/file.tsx(19,2): error TS2322: Type '{ x: number; render: number; }' is not assignable to type 'string'.
@ -18,12 +19,13 @@ tests/cases/conformance/jsx/file.tsx(19,2): error TS2322: Type '{ x: number; ren
}
var Obj1: Obj1type;
<Obj1 x={10} />; // Error, no render member
~~~~~~~~~~~~~~~
!!! error TS2605: JSX element type '{ x: number; }' is not a constructor function for JSX elements.
!!! error TS2605: Property 'render' is missing in type '{ x: number; }' but required in type 'ElementClass'.
!!! related TS2728 tests/cases/conformance/jsx/file.tsx:4:3: 'render' is declared here.
~~~~
!!! error TS2322: Type '{ x: number; }' is not assignable to type 'string'.
~~~~
!!! error TS2786: 'Obj1' cannot be used as a JSX component.
!!! error TS2786: Its instance type '{ x: number; }' is not a valid JSX element.
!!! error TS2786: Property 'render' is missing in type '{ x: number; }' but required in type 'ElementClass'.
!!! related TS2728 tests/cases/conformance/jsx/file.tsx:4:3: 'render' is declared here.
interface Obj2type {
(n: string): { x: number; render: any; };

View file

@ -3,20 +3,22 @@ tests/cases/conformance/jsx/file.tsx(11,2): error TS2769: No overload matches th
Type '{}' is not assignable to type 'string'.
Overload 2 of 2, '(n: number): { y: string; }', gave the following error.
Type '{}' is not assignable to type 'number'.
tests/cases/conformance/jsx/file.tsx(18,1): error TS2605: JSX element type '{ x: number; } & { y: string; }' is not a constructor function for JSX elements.
Property 'something' is missing in type '{ x: number; } & { y: string; }' but required in type 'Element'.
tests/cases/conformance/jsx/file.tsx(18,2): error TS2769: No overload matches this call.
Overload 1 of 2, '(n: string): { x: number; }', gave the following error.
Type '{}' is not assignable to type 'string'.
Overload 2 of 2, '(n: number): { y: string; }', gave the following error.
Type '{}' is not assignable to type 'number'.
tests/cases/conformance/jsx/file.tsx(25,1): error TS2605: JSX element type '{ x: number; } & { x: number; y: string; }' is not a constructor function for JSX elements.
Property 'something' is missing in type '{ x: number; } & { x: number; y: string; }' but required in type 'Element'.
tests/cases/conformance/jsx/file.tsx(18,2): error TS2786: 'Obj2' cannot be used as a JSX component.
Its return type '{ x: number; } & { y: string; }' is not a valid JSX element.
Property 'something' is missing in type '{ x: number; } & { y: string; }' but required in type 'Element'.
tests/cases/conformance/jsx/file.tsx(25,2): error TS2769: No overload matches this call.
Overload 1 of 2, '(n: string): { x: number; }', gave the following error.
Type '{ x: number; }' is not assignable to type 'string'.
Overload 2 of 2, '(n: number): { x: number; y: string; }', gave the following error.
Type '{ x: number; }' is not assignable to type 'number'.
tests/cases/conformance/jsx/file.tsx(25,2): error TS2786: 'Obj3' cannot be used as a JSX component.
Its return type '{ x: number; } & { x: number; y: string; }' is not a valid JSX element.
Property 'something' is missing in type '{ x: number; } & { x: number; y: string; }' but required in type 'Element'.
==== tests/cases/conformance/jsx/file.tsx (5 errors) ====
@ -44,16 +46,17 @@ tests/cases/conformance/jsx/file.tsx(25,2): error TS2769: No overload matches th
}
var Obj2: Obj2;
<Obj2 />; // Error, return type is not an object type
~~~~~~~~
!!! error TS2605: JSX element type '{ x: number; } & { y: string; }' is not a constructor function for JSX elements.
!!! error TS2605: Property 'something' is missing in type '{ x: number; } & { y: string; }' but required in type 'Element'.
!!! related TS2728 tests/cases/conformance/jsx/file.tsx:2:22: 'something' is declared here.
~~~~
!!! error TS2769: No overload matches this call.
!!! error TS2769: Overload 1 of 2, '(n: string): { x: number; }', gave the following error.
!!! error TS2769: Type '{}' is not assignable to type 'string'.
!!! error TS2769: Overload 2 of 2, '(n: number): { y: string; }', gave the following error.
!!! error TS2769: Type '{}' is not assignable to type 'number'.
~~~~
!!! error TS2786: 'Obj2' cannot be used as a JSX component.
!!! error TS2786: Its return type '{ x: number; } & { y: string; }' is not a valid JSX element.
!!! error TS2786: Property 'something' is missing in type '{ x: number; } & { y: string; }' but required in type 'Element'.
!!! related TS2728 tests/cases/conformance/jsx/file.tsx:2:22: 'something' is declared here.
interface Obj3 {
(n: string): { x: number };
@ -61,14 +64,15 @@ tests/cases/conformance/jsx/file.tsx(25,2): error TS2769: No overload matches th
}
var Obj3: Obj3;
<Obj3 x={42} />; // OK
~~~~~~~~~~~~~~~
!!! error TS2605: JSX element type '{ x: number; } & { x: number; y: string; }' is not a constructor function for JSX elements.
!!! error TS2605: Property 'something' is missing in type '{ x: number; } & { x: number; y: string; }' but required in type 'Element'.
!!! related TS2728 tests/cases/conformance/jsx/file.tsx:2:22: 'something' is declared here.
~~~~
!!! error TS2769: No overload matches this call.
!!! error TS2769: Overload 1 of 2, '(n: string): { x: number; }', gave the following error.
!!! error TS2769: Type '{ x: number; }' is not assignable to type 'string'.
!!! error TS2769: Overload 2 of 2, '(n: number): { x: number; y: string; }', gave the following error.
!!! error TS2769: Type '{ x: number; }' is not assignable to type 'number'.
~~~~
!!! error TS2786: 'Obj3' cannot be used as a JSX component.
!!! error TS2786: Its return type '{ x: number; } & { x: number; y: string; }' is not a valid JSX element.
!!! error TS2786: Property 'something' is missing in type '{ x: number; } & { x: number; y: string; }' but required in type 'Element'.
!!! related TS2728 tests/cases/conformance/jsx/file.tsx:2:22: 'something' is declared here.

View file

@ -1,5 +1,7 @@
tests/cases/conformance/jsx/file.tsx(9,13): error TS2605: JSX element type 'undefined' is not a constructor function for JSX elements.
tests/cases/conformance/jsx/file.tsx(10,11): error TS2605: JSX element type 'undefined' is not a constructor function for JSX elements.
tests/cases/conformance/jsx/file.tsx(9,14): error TS2786: 'Foo' cannot be used as a JSX component.
Its return type 'undefined' is not a valid JSX element.
tests/cases/conformance/jsx/file.tsx(10,12): error TS2786: 'Greet' cannot be used as a JSX component.
Its return type 'undefined' is not a valid JSX element.
==== tests/cases/conformance/jsx/file.tsx (2 errors) ====
@ -12,8 +14,10 @@ tests/cases/conformance/jsx/file.tsx(10,11): error TS2605: JSX element type 'und
// Error
const foo = <Foo />;
~~~~~~~
!!! error TS2605: JSX element type 'undefined' is not a constructor function for JSX elements.
~~~
!!! error TS2786: 'Foo' cannot be used as a JSX component.
!!! error TS2786: Its return type 'undefined' is not a valid JSX element.
const G = <Greet />;
~~~~~~~~~
!!! error TS2605: JSX element type 'undefined' is not a constructor function for JSX elements.
~~~~~
!!! error TS2786: 'Greet' cannot be used as a JSX component.
!!! error TS2786: Its return type 'undefined' is not a valid JSX element.

View file

@ -1,4 +1,5 @@
tests/cases/compiler/file.tsx(11,1): error TS2605: JSX element type 'string' is not a constructor function for JSX elements.
tests/cases/compiler/file.tsx(11,2): error TS2786: 'SFC' cannot be used as a JSX component.
Its return type 'string' is not a valid JSX element.
tests/cases/compiler/file.tsx(11,14): error TS2322: Type 'number' is not assignable to type 'string'.
@ -14,8 +15,9 @@ tests/cases/compiler/file.tsx(11,14): error TS2322: Type 'number' is not assigna
}
<SFC<string> prop={1}></SFC>; // should error
~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2605: JSX element type 'string' is not a constructor function for JSX elements.
~~~
!!! error TS2786: 'SFC' cannot be used as a JSX component.
!!! error TS2786: Its return type 'string' is not a valid JSX element.
~~~~
!!! error TS2322: Type 'number' is not assignable to type 'string'.

View file

@ -0,0 +1,40 @@
// @strict: true
// @jsx: preserve
namespace JSX {
export interface Element {
type: 'element';
}
export interface ElementClass {
type: 'element-class';
}
}
function FunctionComponent<T extends string>({type}: {type?: T}) {
return {
type
}
}
FunctionComponent.useThis = function() {
return <this type="foo" />;
}
class ClassComponent {
type = 'string';
}
const MixedComponent = Math.random() ? FunctionComponent : ClassComponent;
const elem1 = <FunctionComponent type="abc" />;
const elem2 = <FunctionComponent<"abc"> />;
const elem3 = <ClassComponent />;
const elem4 = <MixedComponent />;
const obj = {
MemberFunctionComponent() {
return {};
},
MemberClassComponent: class {},
};
const elem5 = <obj.MemberFunctionComponent />;
const elem6 = <obj. MemberClassComponent />;