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:
parent
4c440e5e5b
commit
1f56ab02f0
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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>
|
||||
|
|
103
tests/baselines/reference/jsxComponentTypeErrors.errors.txt
Normal file
103
tests/baselines/reference/jsxComponentTypeErrors.errors.txt
Normal 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.
|
||||
|
75
tests/baselines/reference/jsxComponentTypeErrors.js
Normal file
75
tests/baselines/reference/jsxComponentTypeErrors.js
Normal 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 />;
|
97
tests/baselines/reference/jsxComponentTypeErrors.symbols
Normal file
97
tests/baselines/reference/jsxComponentTypeErrors.symbols
Normal 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))
|
||||
|
107
tests/baselines/reference/jsxComponentTypeErrors.types
Normal file
107
tests/baselines/reference/jsxComponentTypeErrors.types
Normal 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
|
||||
|
|
@ -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; };
|
||||
|
|
|
@ -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.
|
||||
|
|
@ -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.
|
|
@ -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'.
|
||||
|
40
tests/cases/compiler/jsxComponentTypeErrors.tsx
Normal file
40
tests/cases/compiler/jsxComponentTypeErrors.tsx
Normal 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 />;
|
Loading…
Reference in a new issue