From 26e25ae26c7877cecd5235bbe99e850f3563980b Mon Sep 17 00:00:00 2001 From: eps1lon Date: Thu, 27 Oct 2022 12:17:16 +0200 Subject: [PATCH 01/19] jsx: Consult new JSX.ElementType for valid JSX element types --- src/compiler/checker.ts | 21 ++- .../reference/jsxElementType.errors.txt | 118 +++++++++++++ tests/baselines/reference/jsxElementType.js | 133 +++++++++++++++ .../reference/jsxElementType.symbols | 153 +++++++++++++++++ .../baselines/reference/jsxElementType.types | 159 ++++++++++++++++++ tests/cases/compiler/jsxElementType.tsx | 54 ++++++ 6 files changed, 637 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/jsxElementType.errors.txt create mode 100644 tests/baselines/reference/jsxElementType.js create mode 100644 tests/baselines/reference/jsxElementType.symbols create mode 100644 tests/baselines/reference/jsxElementType.types create mode 100644 tests/cases/compiler/jsxElementType.tsx diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 79d6a2fbcdd3c..1b9a36f2b2f16 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -30445,6 +30445,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } + function getJsxElementTypeTypeAt(location: Node): Type | undefined { + const type = getJsxType(JsxNames.ElementType, location); + if (isErrorType(type)) return undefined; + return type; + } + /** * Returns all the properties of the Jsx.IntrinsicElements interface */ @@ -30513,7 +30519,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const jsxOpeningLikeNode = node ; const sig = getResolvedSignature(jsxOpeningLikeNode); checkDeprecatedSignature(sig, node); - checkJsxReturnAssignableToAppropriateBound(getJsxReferenceKind(jsxOpeningLikeNode), getReturnTypeOfSignature(sig), jsxOpeningLikeNode); + + const elementTypeConstraint = getJsxElementTypeTypeAt(jsxOpeningLikeNode); + if (elementTypeConstraint !== undefined) { + const tagType = getApparentType(checkExpression(jsxOpeningLikeNode.tagName)); + // TODO: error message + checkTypeRelatedTo(tagType, elementTypeConstraint, comparableRelation, jsxOpeningLikeNode.tagName, Diagnostics.Its_instance_type_0_is_not_a_valid_JSX_element, () => { + const componentName = getTextOfNode(jsxOpeningLikeNode.tagName); + return chainDiagnosticMessages(/* details */ undefined, Diagnostics._0_cannot_be_used_as_a_JSX_component, componentName); + }); + } + else { + checkJsxReturnAssignableToAppropriateBound(getJsxReferenceKind(jsxOpeningLikeNode), getReturnTypeOfSignature(sig), jsxOpeningLikeNode); + } } } @@ -48361,6 +48379,7 @@ namespace JsxNames { export const ElementAttributesPropertyNameContainer = "ElementAttributesProperty" as __String; // TODO: Deprecate and remove support export const ElementChildrenAttributeNameContainer = "ElementChildrenAttribute" as __String; export const Element = "Element" as __String; + export const ElementType = "ElementType" as __String; export const IntrinsicAttributes = "IntrinsicAttributes" as __String; export const IntrinsicClassAttributes = "IntrinsicClassAttributes" as __String; export const LibraryManagedAttributes = "LibraryManagedAttributes" as __String; diff --git a/tests/baselines/reference/jsxElementType.errors.txt b/tests/baselines/reference/jsxElementType.errors.txt new file mode 100644 index 0000000000000..86c01340cd3f7 --- /dev/null +++ b/tests/baselines/reference/jsxElementType.errors.txt @@ -0,0 +1,118 @@ +tests/cases/compiler/jsxElementType.tsx(30,2): error TS2741: Property 'title' is missing in type '{}' but required in type '{ title: string; }'. +tests/cases/compiler/jsxElementType.tsx(32,15): error TS2322: Type '{ excessProp: true; }' is not assignable to type 'IntrinsicAttributes & { title: string; }'. + Property 'excessProp' does not exist on type 'IntrinsicAttributes & { title: string; }'. +tests/cases/compiler/jsxElementType.tsx(36,2): error TS2741: Property 'title' is missing in type '{}' but required in type '{ title: string; }'. +tests/cases/compiler/jsxElementType.tsx(38,15): error TS2322: Type '{ excessProp: true; }' is not assignable to type 'IntrinsicAttributes & { title: string; }'. + Property 'excessProp' does not exist on type 'IntrinsicAttributes & { title: string; }'. +tests/cases/compiler/jsxElementType.tsx(42,2): error TS2741: Property 'title' is missing in type '{}' but required in type '{ title: string; }'. +tests/cases/compiler/jsxElementType.tsx(44,14): error TS2322: Type '{ excessProp: true; }' is not assignable to type 'IntrinsicAttributes & { title: string; }'. + Property 'excessProp' does not exist on type 'IntrinsicAttributes & { title: string; }'. +tests/cases/compiler/jsxElementType.tsx(49,1): error TS2322: Type '({ title }: { title: string; }) => Promise' is not assignable to type 'ElementType'. + Type '({ title }: { title: string; }) => Promise' is not assignable to type '(props: any) => React18ReactNode'. + Type 'Promise' is not assignable to type 'React18ReactNode'. +tests/cases/compiler/jsxElementType.tsx(50,2): error TS2741: Property 'title' is missing in type '{}' but required in type '{ title: string; }'. +tests/cases/compiler/jsxElementType.tsx(50,2): error TS2786: 'RenderPromise' cannot be used as a JSX component. + Its instance type '({ title }: { title: string; }) => Promise' is not a valid JSX element. + Type '({ title }: { title: string; }) => Promise' is not comparable to type '(props: Props) => React18ReactNode'. + Type 'Promise' is not comparable to type 'React18ReactNode'. +tests/cases/compiler/jsxElementType.tsx(51,2): error TS2786: 'RenderPromise' cannot be used as a JSX component. + Its instance type '({ title }: { title: string; }) => Promise' is not a valid JSX element. +tests/cases/compiler/jsxElementType.tsx(52,2): error TS2786: 'RenderPromise' cannot be used as a JSX component. + Its instance type '({ title }: { title: string; }) => Promise' is not a valid JSX element. +tests/cases/compiler/jsxElementType.tsx(52,16): error TS2322: Type '{ excessProp: true; }' is not assignable to type 'IntrinsicAttributes & { title: string; }'. + Property 'excessProp' does not exist on type 'IntrinsicAttributes & { title: string; }'. + + +==== tests/cases/compiler/jsxElementType.tsx (12 errors) ==== + /// + import * as React from "react"; + + type React18ReactFragment = ReadonlyArray; + type React18ReactNode = + | React.ReactElement + | string + | number + | React18ReactFragment + | React.ReactPortal + | boolean + | null + | undefined; + + // // React.JSXElementConstructor but it now can return React nodes from function components. + type NewReactJSXElementConstructor

= + | ((props: P) => React18ReactNode) + | (new (props: P) => React.Component); + + declare global { + namespace JSX { + type ElementType = string | NewReactJSXElementConstructor; + } + } + + let Component: JSX.ElementType; + + const RenderString = ({ title }: { title: string }) => title; + Component = RenderString; + ; + ~~~~~~~~~~~~ +!!! error TS2741: Property 'title' is missing in type '{}' but required in type '{ title: string; }'. +!!! related TS2728 tests/cases/compiler/jsxElementType.tsx:28:36: 'title' is declared here. + ; + ; + ~~~~~~~~~~ +!!! error TS2322: Type '{ excessProp: true; }' is not assignable to type 'IntrinsicAttributes & { title: string; }'. +!!! error TS2322: Property 'excessProp' does not exist on type 'IntrinsicAttributes & { title: string; }'. + + const RenderNumber = ({ title }: { title: string }) => title.length; + Component = RenderNumber; + ; + ~~~~~~~~~~~~ +!!! error TS2741: Property 'title' is missing in type '{}' but required in type '{ title: string; }'. +!!! related TS2728 tests/cases/compiler/jsxElementType.tsx:34:36: 'title' is declared here. + ; + ; + ~~~~~~~~~~ +!!! error TS2322: Type '{ excessProp: true; }' is not assignable to type 'IntrinsicAttributes & { title: string; }'. +!!! error TS2322: Property 'excessProp' does not exist on type 'IntrinsicAttributes & { title: string; }'. + + const RenderArray = ({ title }: { title: string }) => [title]; + Component = RenderArray; + ; + ~~~~~~~~~~~ +!!! error TS2741: Property 'title' is missing in type '{}' but required in type '{ title: string; }'. +!!! related TS2728 tests/cases/compiler/jsxElementType.tsx:40:35: 'title' is declared here. + ; + ; + ~~~~~~~~~~ +!!! error TS2322: Type '{ excessProp: true; }' is not assignable to type 'IntrinsicAttributes & { title: string; }'. +!!! error TS2322: Property 'excessProp' does not exist on type 'IntrinsicAttributes & { title: string; }'. + + // Future ReactNode can be Promises. + // But they should be rejected in React 18.0. + const RenderPromise = async ({ title }: { title: string }) => "react"; + Component = RenderPromise; + ~~~~~~~~~ +!!! error TS2322: Type '({ title }: { title: string; }) => Promise' is not assignable to type 'ElementType'. +!!! error TS2322: Type '({ title }: { title: string; }) => Promise' is not assignable to type '(props: any) => React18ReactNode'. +!!! error TS2322: Type 'Promise' is not assignable to type 'React18ReactNode'. + ; + ~~~~~~~~~~~~~ +!!! error TS2741: Property 'title' is missing in type '{}' but required in type '{ title: string; }'. +!!! related TS2728 tests/cases/compiler/jsxElementType.tsx:48:43: 'title' is declared here. + ~~~~~~~~~~~~~ +!!! error TS2786: 'RenderPromise' cannot be used as a JSX component. +!!! error TS2786: Its instance type '({ title }: { title: string; }) => Promise' is not a valid JSX element. +!!! error TS2786: Type '({ title }: { title: string; }) => Promise' is not comparable to type '(props: Props) => React18ReactNode'. +!!! error TS2786: Type 'Promise' is not comparable to type 'React18ReactNode'. + ; + ~~~~~~~~~~~~~ +!!! error TS2786: 'RenderPromise' cannot be used as a JSX component. +!!! error TS2786: Its instance type '({ title }: { title: string; }) => Promise' is not a valid JSX element. + ; + ~~~~~~~~~~~~~ +!!! error TS2786: 'RenderPromise' cannot be used as a JSX component. +!!! error TS2786: Its instance type '({ title }: { title: string; }) => Promise' is not a valid JSX element. + ~~~~~~~~~~ +!!! error TS2322: Type '{ excessProp: true; }' is not assignable to type 'IntrinsicAttributes & { title: string; }'. +!!! error TS2322: Property 'excessProp' does not exist on type 'IntrinsicAttributes & { title: string; }'. + \ No newline at end of file diff --git a/tests/baselines/reference/jsxElementType.js b/tests/baselines/reference/jsxElementType.js new file mode 100644 index 0000000000000..b8d4dd5b2aef3 --- /dev/null +++ b/tests/baselines/reference/jsxElementType.js @@ -0,0 +1,133 @@ +//// [jsxElementType.tsx] +/// +import * as React from "react"; + +type React18ReactFragment = ReadonlyArray; +type React18ReactNode = + | React.ReactElement + | string + | number + | React18ReactFragment + | React.ReactPortal + | boolean + | null + | undefined; + +// // React.JSXElementConstructor but it now can return React nodes from function components. +type NewReactJSXElementConstructor

= + | ((props: P) => React18ReactNode) + | (new (props: P) => React.Component); + +declare global { + namespace JSX { + type ElementType = string | NewReactJSXElementConstructor; + } +} + +let Component: JSX.ElementType; + +const RenderString = ({ title }: { title: string }) => title; +Component = RenderString; +; +; +; + +const RenderNumber = ({ title }: { title: string }) => title.length; +Component = RenderNumber; +; +; +; + +const RenderArray = ({ title }: { title: string }) => [title]; +Component = RenderArray; +; +; +; + +// Future ReactNode can be Promises. +// But they should be rejected in React 18.0. +const RenderPromise = async ({ title }: { title: string }) => "react"; +Component = RenderPromise; +; +; +; + + +//// [jsxElementType.js] +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +exports.__esModule = true; +/// +var React = require("react"); +var Component; +var RenderString = function (_a) { + var title = _a.title; + return title; +}; +Component = RenderString; +React.createElement(RenderString, null); +React.createElement(RenderString, { title: "react" }); +React.createElement(RenderString, { excessProp: true }); +var RenderNumber = function (_a) { + var title = _a.title; + return title.length; +}; +Component = RenderNumber; +React.createElement(RenderNumber, null); +React.createElement(RenderNumber, { title: "react" }); +React.createElement(RenderNumber, { excessProp: true }); +var RenderArray = function (_a) { + var title = _a.title; + return [title]; +}; +Component = RenderArray; +React.createElement(RenderArray, null); +React.createElement(RenderArray, { title: "react" }); +React.createElement(RenderArray, { excessProp: true }); +// Future ReactNode can be Promises. +// But they should be rejected in React 18.0. +var RenderPromise = function (_a) { + var title = _a.title; + return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_b) { + return [2 /*return*/, "react"]; + }); }); +}; +Component = RenderPromise; +React.createElement(RenderPromise, null); +React.createElement(RenderPromise, { title: "react" }); +React.createElement(RenderPromise, { excessProp: true }); diff --git a/tests/baselines/reference/jsxElementType.symbols b/tests/baselines/reference/jsxElementType.symbols new file mode 100644 index 0000000000000..e5411e266a88a --- /dev/null +++ b/tests/baselines/reference/jsxElementType.symbols @@ -0,0 +1,153 @@ +=== tests/cases/compiler/jsxElementType.tsx === +/// +import * as React from "react"; +>React : Symbol(React, Decl(jsxElementType.tsx, 1, 6)) + +type React18ReactFragment = ReadonlyArray; +>React18ReactFragment : Symbol(React18ReactFragment, Decl(jsxElementType.tsx, 1, 31)) +>ReadonlyArray : Symbol(ReadonlyArray, Decl(lib.es5.d.ts, --, --)) +>React18ReactNode : Symbol(React18ReactNode, Decl(jsxElementType.tsx, 3, 60)) + +type React18ReactNode = +>React18ReactNode : Symbol(React18ReactNode, Decl(jsxElementType.tsx, 3, 60)) + + | React.ReactElement +>React : Symbol(React, Decl(jsxElementType.tsx, 1, 6)) +>ReactElement : Symbol(React.ReactElement, Decl(react16.d.ts, 135, 9)) + + | string + | number + | React18ReactFragment +>React18ReactFragment : Symbol(React18ReactFragment, Decl(jsxElementType.tsx, 1, 31)) + + | React.ReactPortal +>React : Symbol(React, Decl(jsxElementType.tsx, 1, 6)) +>ReactPortal : Symbol(React.ReactPortal, Decl(react16.d.ts, 172, 9)) + + | boolean + | null + | undefined; + +// // React.JSXElementConstructor but it now can return React nodes from function components. +type NewReactJSXElementConstructor

= +>NewReactJSXElementConstructor : Symbol(NewReactJSXElementConstructor, Decl(jsxElementType.tsx, 12, 14)) +>P : Symbol(P, Decl(jsxElementType.tsx, 15, 35)) + + | ((props: P) => React18ReactNode) +>props : Symbol(props, Decl(jsxElementType.tsx, 16, 6)) +>P : Symbol(P, Decl(jsxElementType.tsx, 15, 35)) +>React18ReactNode : Symbol(React18ReactNode, Decl(jsxElementType.tsx, 3, 60)) + + | (new (props: P) => React.Component); +>props : Symbol(props, Decl(jsxElementType.tsx, 17, 10)) +>P : Symbol(P, Decl(jsxElementType.tsx, 15, 35)) +>React : Symbol(React, Decl(jsxElementType.tsx, 1, 6)) +>Component : Symbol(React.Component, Decl(react16.d.ts, 345, 54), Decl(react16.d.ts, 349, 94)) +>P : Symbol(P, Decl(jsxElementType.tsx, 15, 35)) + +declare global { +>global : Symbol(global, Decl(jsxElementType.tsx, 17, 48)) + + namespace JSX { +>JSX : Symbol(JSX, Decl(react16.d.ts, 2493, 12), Decl(jsxElementType.tsx, 19, 16)) + + type ElementType = string | NewReactJSXElementConstructor; +>ElementType : Symbol(ElementType, Decl(jsxElementType.tsx, 20, 17)) +>Props : Symbol(Props, Decl(jsxElementType.tsx, 21, 21)) +>NewReactJSXElementConstructor : Symbol(NewReactJSXElementConstructor, Decl(jsxElementType.tsx, 12, 14)) +>Props : Symbol(Props, Decl(jsxElementType.tsx, 21, 21)) + } +} + +let Component: JSX.ElementType; +>Component : Symbol(Component, Decl(jsxElementType.tsx, 25, 3)) +>JSX : Symbol(JSX, Decl(react16.d.ts, 2493, 12), Decl(jsxElementType.tsx, 19, 16)) +>ElementType : Symbol(JSX.ElementType, Decl(jsxElementType.tsx, 20, 17)) + +const RenderString = ({ title }: { title: string }) => title; +>RenderString : Symbol(RenderString, Decl(jsxElementType.tsx, 27, 5)) +>title : Symbol(title, Decl(jsxElementType.tsx, 27, 23)) +>title : Symbol(title, Decl(jsxElementType.tsx, 27, 34)) +>title : Symbol(title, Decl(jsxElementType.tsx, 27, 23)) + +Component = RenderString; +>Component : Symbol(Component, Decl(jsxElementType.tsx, 25, 3)) +>RenderString : Symbol(RenderString, Decl(jsxElementType.tsx, 27, 5)) + +; +>RenderString : Symbol(RenderString, Decl(jsxElementType.tsx, 27, 5)) + +; +>RenderString : Symbol(RenderString, Decl(jsxElementType.tsx, 27, 5)) +>title : Symbol(title, Decl(jsxElementType.tsx, 30, 13)) + +; +>RenderString : Symbol(RenderString, Decl(jsxElementType.tsx, 27, 5)) +>excessProp : Symbol(excessProp, Decl(jsxElementType.tsx, 31, 13)) + +const RenderNumber = ({ title }: { title: string }) => title.length; +>RenderNumber : Symbol(RenderNumber, Decl(jsxElementType.tsx, 33, 5)) +>title : Symbol(title, Decl(jsxElementType.tsx, 33, 23)) +>title : Symbol(title, Decl(jsxElementType.tsx, 33, 34)) +>title.length : Symbol(String.length, Decl(lib.es5.d.ts, --, --)) +>title : Symbol(title, Decl(jsxElementType.tsx, 33, 23)) +>length : Symbol(String.length, Decl(lib.es5.d.ts, --, --)) + +Component = RenderNumber; +>Component : Symbol(Component, Decl(jsxElementType.tsx, 25, 3)) +>RenderNumber : Symbol(RenderNumber, Decl(jsxElementType.tsx, 33, 5)) + +; +>RenderNumber : Symbol(RenderNumber, Decl(jsxElementType.tsx, 33, 5)) + +; +>RenderNumber : Symbol(RenderNumber, Decl(jsxElementType.tsx, 33, 5)) +>title : Symbol(title, Decl(jsxElementType.tsx, 36, 13)) + +; +>RenderNumber : Symbol(RenderNumber, Decl(jsxElementType.tsx, 33, 5)) +>excessProp : Symbol(excessProp, Decl(jsxElementType.tsx, 37, 13)) + +const RenderArray = ({ title }: { title: string }) => [title]; +>RenderArray : Symbol(RenderArray, Decl(jsxElementType.tsx, 39, 5)) +>title : Symbol(title, Decl(jsxElementType.tsx, 39, 22)) +>title : Symbol(title, Decl(jsxElementType.tsx, 39, 33)) +>title : Symbol(title, Decl(jsxElementType.tsx, 39, 22)) + +Component = RenderArray; +>Component : Symbol(Component, Decl(jsxElementType.tsx, 25, 3)) +>RenderArray : Symbol(RenderArray, Decl(jsxElementType.tsx, 39, 5)) + +; +>RenderArray : Symbol(RenderArray, Decl(jsxElementType.tsx, 39, 5)) + +; +>RenderArray : Symbol(RenderArray, Decl(jsxElementType.tsx, 39, 5)) +>title : Symbol(title, Decl(jsxElementType.tsx, 42, 12)) + +; +>RenderArray : Symbol(RenderArray, Decl(jsxElementType.tsx, 39, 5)) +>excessProp : Symbol(excessProp, Decl(jsxElementType.tsx, 43, 12)) + +// Future ReactNode can be Promises. +// But they should be rejected in React 18.0. +const RenderPromise = async ({ title }: { title: string }) => "react"; +>RenderPromise : Symbol(RenderPromise, Decl(jsxElementType.tsx, 47, 5)) +>title : Symbol(title, Decl(jsxElementType.tsx, 47, 30)) +>title : Symbol(title, Decl(jsxElementType.tsx, 47, 41)) + +Component = RenderPromise; +>Component : Symbol(Component, Decl(jsxElementType.tsx, 25, 3)) +>RenderPromise : Symbol(RenderPromise, Decl(jsxElementType.tsx, 47, 5)) + +; +>RenderPromise : Symbol(RenderPromise, Decl(jsxElementType.tsx, 47, 5)) + +; +>RenderPromise : Symbol(RenderPromise, Decl(jsxElementType.tsx, 47, 5)) +>title : Symbol(title, Decl(jsxElementType.tsx, 50, 14)) + +; +>RenderPromise : Symbol(RenderPromise, Decl(jsxElementType.tsx, 47, 5)) +>excessProp : Symbol(excessProp, Decl(jsxElementType.tsx, 51, 14)) + diff --git a/tests/baselines/reference/jsxElementType.types b/tests/baselines/reference/jsxElementType.types new file mode 100644 index 0000000000000..ae989e9820655 --- /dev/null +++ b/tests/baselines/reference/jsxElementType.types @@ -0,0 +1,159 @@ +=== tests/cases/compiler/jsxElementType.tsx === +/// +import * as React from "react"; +>React : typeof React + +type React18ReactFragment = ReadonlyArray; +>React18ReactFragment : readonly React18ReactNode[] + +type React18ReactNode = +>React18ReactNode : string | number | boolean | React.ReactElement | React.ReactPortal | React18ReactFragment | null | undefined + + | React.ReactElement +>React : any + + | string + | number + | React18ReactFragment + | React.ReactPortal +>React : any + + | boolean + | null +>null : null + + | undefined; + +// // React.JSXElementConstructor but it now can return React nodes from function components. +type NewReactJSXElementConstructor

= +>NewReactJSXElementConstructor : NewReactJSXElementConstructor

+ + | ((props: P) => React18ReactNode) +>props : P + + | (new (props: P) => React.Component); +>props : P +>React : any + +declare global { +>global : any + + namespace JSX { + type ElementType = string | NewReactJSXElementConstructor; +>ElementType : ElementType + } +} + +let Component: JSX.ElementType; +>Component : JSX.ElementType +>JSX : any + +const RenderString = ({ title }: { title: string }) => title; +>RenderString : ({ title }: { title: string; }) => string +>({ title }: { title: string }) => title : ({ title }: { title: string; }) => string +>title : string +>title : string +>title : string + +Component = RenderString; +>Component = RenderString : ({ title }: { title: string; }) => string +>Component : JSX.ElementType +>RenderString : ({ title }: { title: string; }) => string + +; +> : JSX.Element +>RenderString : ({ title }: { title: string; }) => string + +; +> : JSX.Element +>RenderString : ({ title }: { title: string; }) => string +>title : string + +; +> : JSX.Element +>RenderString : ({ title }: { title: string; }) => string +>excessProp : true + +const RenderNumber = ({ title }: { title: string }) => title.length; +>RenderNumber : ({ title }: { title: string; }) => number +>({ title }: { title: string }) => title.length : ({ title }: { title: string; }) => number +>title : string +>title : string +>title.length : number +>title : string +>length : number + +Component = RenderNumber; +>Component = RenderNumber : ({ title }: { title: string; }) => number +>Component : JSX.ElementType +>RenderNumber : ({ title }: { title: string; }) => number + +; +> : JSX.Element +>RenderNumber : ({ title }: { title: string; }) => number + +; +> : JSX.Element +>RenderNumber : ({ title }: { title: string; }) => number +>title : string + +; +> : JSX.Element +>RenderNumber : ({ title }: { title: string; }) => number +>excessProp : true + +const RenderArray = ({ title }: { title: string }) => [title]; +>RenderArray : ({ title }: { title: string; }) => string[] +>({ title }: { title: string }) => [title] : ({ title }: { title: string; }) => string[] +>title : string +>title : string +>[title] : string[] +>title : string + +Component = RenderArray; +>Component = RenderArray : ({ title }: { title: string; }) => string[] +>Component : JSX.ElementType +>RenderArray : ({ title }: { title: string; }) => string[] + +; +> : JSX.Element +>RenderArray : ({ title }: { title: string; }) => string[] + +; +> : JSX.Element +>RenderArray : ({ title }: { title: string; }) => string[] +>title : string + +; +> : JSX.Element +>RenderArray : ({ title }: { title: string; }) => string[] +>excessProp : true + +// Future ReactNode can be Promises. +// But they should be rejected in React 18.0. +const RenderPromise = async ({ title }: { title: string }) => "react"; +>RenderPromise : ({ title }: { title: string; }) => Promise +>async ({ title }: { title: string }) => "react" : ({ title }: { title: string; }) => Promise +>title : string +>title : string +>"react" : "react" + +Component = RenderPromise; +>Component = RenderPromise : ({ title }: { title: string; }) => Promise +>Component : JSX.ElementType +>RenderPromise : ({ title }: { title: string; }) => Promise + +; +> : JSX.Element +>RenderPromise : ({ title }: { title: string; }) => Promise + +; +> : JSX.Element +>RenderPromise : ({ title }: { title: string; }) => Promise +>title : string + +; +> : JSX.Element +>RenderPromise : ({ title }: { title: string; }) => Promise +>excessProp : true + diff --git a/tests/cases/compiler/jsxElementType.tsx b/tests/cases/compiler/jsxElementType.tsx new file mode 100644 index 0000000000000..aafdd4459577a --- /dev/null +++ b/tests/cases/compiler/jsxElementType.tsx @@ -0,0 +1,54 @@ +// @strict: true +// @jsx: react +/// +import * as React from "react"; + +type React18ReactFragment = ReadonlyArray; +type React18ReactNode = + | React.ReactElement + | string + | number + | React18ReactFragment + | React.ReactPortal + | boolean + | null + | undefined; + +// // React.JSXElementConstructor but it now can return React nodes from function components. +type NewReactJSXElementConstructor

= + | ((props: P) => React18ReactNode) + | (new (props: P) => React.Component); + +declare global { + namespace JSX { + type ElementType = string | NewReactJSXElementConstructor; + } +} + +let Component: JSX.ElementType; + +const RenderString = ({ title }: { title: string }) => title; +Component = RenderString; +; +; +; + +const RenderNumber = ({ title }: { title: string }) => title.length; +Component = RenderNumber; +; +; +; + +const RenderArray = ({ title }: { title: string }) => [title]; +Component = RenderArray; +; +; +; + +// Future ReactNode can be Promises. +// But they should be rejected in React 18.0. +const RenderPromise = async ({ title }: { title: string }) => "react"; +Component = RenderPromise; +; +; +; From 71a08436feeaf710a78d397f16d88b5db7872121 Mon Sep 17 00:00:00 2001 From: eps1lon Date: Thu, 27 Oct 2022 12:35:02 +0200 Subject: [PATCH 02/19] Stricter impl of `JSX.ElementType` --- .../baselines/reference/jsxElementType.errors.txt | 12 ++++++------ tests/baselines/reference/jsxElementType.js | 4 ++-- tests/baselines/reference/jsxElementType.symbols | 5 +++-- tests/baselines/reference/jsxElementType.types | 15 ++++++++------- tests/cases/compiler/jsxElementType.tsx | 4 ++-- 5 files changed, 21 insertions(+), 19 deletions(-) diff --git a/tests/baselines/reference/jsxElementType.errors.txt b/tests/baselines/reference/jsxElementType.errors.txt index 86c01340cd3f7..0438890cc11d5 100644 --- a/tests/baselines/reference/jsxElementType.errors.txt +++ b/tests/baselines/reference/jsxElementType.errors.txt @@ -7,8 +7,8 @@ tests/cases/compiler/jsxElementType.tsx(38,15): error TS2322: Type '{ excessProp tests/cases/compiler/jsxElementType.tsx(42,2): error TS2741: Property 'title' is missing in type '{}' but required in type '{ title: string; }'. tests/cases/compiler/jsxElementType.tsx(44,14): error TS2322: Type '{ excessProp: true; }' is not assignable to type 'IntrinsicAttributes & { title: string; }'. Property 'excessProp' does not exist on type 'IntrinsicAttributes & { title: string; }'. -tests/cases/compiler/jsxElementType.tsx(49,1): error TS2322: Type '({ title }: { title: string; }) => Promise' is not assignable to type 'ElementType'. - Type '({ title }: { title: string; }) => Promise' is not assignable to type '(props: any) => React18ReactNode'. +tests/cases/compiler/jsxElementType.tsx(49,1): error TS2322: Type '({ title }: { title: string; }) => Promise' is not assignable to type 'ElementType<{ title: string; }>'. + Type '({ title }: { title: string; }) => Promise' is not assignable to type '(props: { title: string; }) => React18ReactNode'. Type 'Promise' is not assignable to type 'React18ReactNode'. tests/cases/compiler/jsxElementType.tsx(50,2): error TS2741: Property 'title' is missing in type '{}' but required in type '{ title: string; }'. tests/cases/compiler/jsxElementType.tsx(50,2): error TS2786: 'RenderPromise' cannot be used as a JSX component. @@ -45,11 +45,11 @@ tests/cases/compiler/jsxElementType.tsx(52,16): error TS2322: Type '{ excessProp declare global { namespace JSX { - type ElementType = string | NewReactJSXElementConstructor; + type ElementType = string | NewReactJSXElementConstructor; } } - let Component: JSX.ElementType; + let Component: JSX.ElementType<{ title: string }>; const RenderString = ({ title }: { title: string }) => title; Component = RenderString; @@ -92,8 +92,8 @@ tests/cases/compiler/jsxElementType.tsx(52,16): error TS2322: Type '{ excessProp const RenderPromise = async ({ title }: { title: string }) => "react"; Component = RenderPromise; ~~~~~~~~~ -!!! error TS2322: Type '({ title }: { title: string; }) => Promise' is not assignable to type 'ElementType'. -!!! error TS2322: Type '({ title }: { title: string; }) => Promise' is not assignable to type '(props: any) => React18ReactNode'. +!!! error TS2322: Type '({ title }: { title: string; }) => Promise' is not assignable to type 'ElementType<{ title: string; }>'. +!!! error TS2322: Type '({ title }: { title: string; }) => Promise' is not assignable to type '(props: { title: string; }) => React18ReactNode'. !!! error TS2322: Type 'Promise' is not assignable to type 'React18ReactNode'. ; ~~~~~~~~~~~~~ diff --git a/tests/baselines/reference/jsxElementType.js b/tests/baselines/reference/jsxElementType.js index b8d4dd5b2aef3..d193717017e41 100644 --- a/tests/baselines/reference/jsxElementType.js +++ b/tests/baselines/reference/jsxElementType.js @@ -20,11 +20,11 @@ type NewReactJSXElementConstructor

= declare global { namespace JSX { - type ElementType = string | NewReactJSXElementConstructor; + type ElementType = string | NewReactJSXElementConstructor; } } -let Component: JSX.ElementType; +let Component: JSX.ElementType<{ title: string }>; const RenderString = ({ title }: { title: string }) => title; Component = RenderString; diff --git a/tests/baselines/reference/jsxElementType.symbols b/tests/baselines/reference/jsxElementType.symbols index e5411e266a88a..531230d409ad4 100644 --- a/tests/baselines/reference/jsxElementType.symbols +++ b/tests/baselines/reference/jsxElementType.symbols @@ -51,7 +51,7 @@ declare global { namespace JSX { >JSX : Symbol(JSX, Decl(react16.d.ts, 2493, 12), Decl(jsxElementType.tsx, 19, 16)) - type ElementType = string | NewReactJSXElementConstructor; + type ElementType = string | NewReactJSXElementConstructor; >ElementType : Symbol(ElementType, Decl(jsxElementType.tsx, 20, 17)) >Props : Symbol(Props, Decl(jsxElementType.tsx, 21, 21)) >NewReactJSXElementConstructor : Symbol(NewReactJSXElementConstructor, Decl(jsxElementType.tsx, 12, 14)) @@ -59,10 +59,11 @@ declare global { } } -let Component: JSX.ElementType; +let Component: JSX.ElementType<{ title: string }>; >Component : Symbol(Component, Decl(jsxElementType.tsx, 25, 3)) >JSX : Symbol(JSX, Decl(react16.d.ts, 2493, 12), Decl(jsxElementType.tsx, 19, 16)) >ElementType : Symbol(JSX.ElementType, Decl(jsxElementType.tsx, 20, 17)) +>title : Symbol(title, Decl(jsxElementType.tsx, 25, 32)) const RenderString = ({ title }: { title: string }) => title; >RenderString : Symbol(RenderString, Decl(jsxElementType.tsx, 27, 5)) diff --git a/tests/baselines/reference/jsxElementType.types b/tests/baselines/reference/jsxElementType.types index ae989e9820655..e84b26bde68ea 100644 --- a/tests/baselines/reference/jsxElementType.types +++ b/tests/baselines/reference/jsxElementType.types @@ -39,14 +39,15 @@ declare global { >global : any namespace JSX { - type ElementType = string | NewReactJSXElementConstructor; + type ElementType = string | NewReactJSXElementConstructor; >ElementType : ElementType } } -let Component: JSX.ElementType; ->Component : JSX.ElementType +let Component: JSX.ElementType<{ title: string }>; +>Component : JSX.ElementType<{ title: string; }> >JSX : any +>title : string const RenderString = ({ title }: { title: string }) => title; >RenderString : ({ title }: { title: string; }) => string @@ -57,7 +58,7 @@ const RenderString = ({ title }: { title: string }) => title; Component = RenderString; >Component = RenderString : ({ title }: { title: string; }) => string ->Component : JSX.ElementType +>Component : JSX.ElementType<{ title: string; }> >RenderString : ({ title }: { title: string; }) => string ; @@ -85,7 +86,7 @@ const RenderNumber = ({ title }: { title: string }) => title.length; Component = RenderNumber; >Component = RenderNumber : ({ title }: { title: string; }) => number ->Component : JSX.ElementType +>Component : JSX.ElementType<{ title: string; }> >RenderNumber : ({ title }: { title: string; }) => number ; @@ -112,7 +113,7 @@ const RenderArray = ({ title }: { title: string }) => [title]; Component = RenderArray; >Component = RenderArray : ({ title }: { title: string; }) => string[] ->Component : JSX.ElementType +>Component : JSX.ElementType<{ title: string; }> >RenderArray : ({ title }: { title: string; }) => string[] ; @@ -140,7 +141,7 @@ const RenderPromise = async ({ title }: { title: string }) => "react"; Component = RenderPromise; >Component = RenderPromise : ({ title }: { title: string; }) => Promise ->Component : JSX.ElementType +>Component : JSX.ElementType<{ title: string; }> >RenderPromise : ({ title }: { title: string; }) => Promise ; diff --git a/tests/cases/compiler/jsxElementType.tsx b/tests/cases/compiler/jsxElementType.tsx index aafdd4459577a..d56a751a3b500 100644 --- a/tests/cases/compiler/jsxElementType.tsx +++ b/tests/cases/compiler/jsxElementType.tsx @@ -21,11 +21,11 @@ type NewReactJSXElementConstructor

= declare global { namespace JSX { - type ElementType = string | NewReactJSXElementConstructor; + type ElementType = string | NewReactJSXElementConstructor; } } -let Component: JSX.ElementType; +let Component: JSX.ElementType<{ title: string }>; const RenderString = ({ title }: { title: string }) => title; Component = RenderString; From ca648a8869a34169eeddb91102db6155d4b3dc8d Mon Sep 17 00:00:00 2001 From: Sebastian Silbermann Date: Tue, 14 Feb 2023 14:07:19 +0100 Subject: [PATCH 03/19] Update baseline --- tests/baselines/reference/jsxElementType.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/baselines/reference/jsxElementType.js b/tests/baselines/reference/jsxElementType.js index d193717017e41..eacc87ddc094c 100644 --- a/tests/baselines/reference/jsxElementType.js +++ b/tests/baselines/reference/jsxElementType.js @@ -91,7 +91,7 @@ var __generator = (this && this.__generator) || function (thisArg, body) { if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; -exports.__esModule = true; +Object.defineProperty(exports, "__esModule", { value: true }); /// var React = require("react"); var Component; From 8bda7072a736635e52fd81dfb671ca243d08b8b4 Mon Sep 17 00:00:00 2001 From: Sebastian Silbermann Date: Tue, 14 Feb 2023 15:56:28 +0100 Subject: [PATCH 04/19] Remove props type param Allows using common assignability instead of compareability relation. Added a test for ecosystem compat issues. --- src/compiler/checker.ts | 2 +- .../reference/jsxElementType.errors.txt | 38 +++++++++++++----- tests/baselines/reference/jsxElementType.js | 21 ++++++++-- .../reference/jsxElementType.symbols | 36 +++++++++++++---- .../baselines/reference/jsxElementType.types | 40 ++++++++++++++----- tests/cases/compiler/jsxElementType.tsx | 16 +++++++- 6 files changed, 121 insertions(+), 32 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 1b9a36f2b2f16..27ec4e1da7e4b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -30524,7 +30524,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (elementTypeConstraint !== undefined) { const tagType = getApparentType(checkExpression(jsxOpeningLikeNode.tagName)); // TODO: error message - checkTypeRelatedTo(tagType, elementTypeConstraint, comparableRelation, jsxOpeningLikeNode.tagName, Diagnostics.Its_instance_type_0_is_not_a_valid_JSX_element, () => { + checkTypeRelatedTo(tagType, elementTypeConstraint, assignableRelation, jsxOpeningLikeNode.tagName, Diagnostics.Its_instance_type_0_is_not_a_valid_JSX_element, () => { const componentName = getTextOfNode(jsxOpeningLikeNode.tagName); return chainDiagnosticMessages(/* details */ undefined, Diagnostics._0_cannot_be_used_as_a_JSX_component, componentName); }); diff --git a/tests/baselines/reference/jsxElementType.errors.txt b/tests/baselines/reference/jsxElementType.errors.txt index 0438890cc11d5..43c52457316b6 100644 --- a/tests/baselines/reference/jsxElementType.errors.txt +++ b/tests/baselines/reference/jsxElementType.errors.txt @@ -7,23 +7,26 @@ tests/cases/compiler/jsxElementType.tsx(38,15): error TS2322: Type '{ excessProp tests/cases/compiler/jsxElementType.tsx(42,2): error TS2741: Property 'title' is missing in type '{}' but required in type '{ title: string; }'. tests/cases/compiler/jsxElementType.tsx(44,14): error TS2322: Type '{ excessProp: true; }' is not assignable to type 'IntrinsicAttributes & { title: string; }'. Property 'excessProp' does not exist on type 'IntrinsicAttributes & { title: string; }'. -tests/cases/compiler/jsxElementType.tsx(49,1): error TS2322: Type '({ title }: { title: string; }) => Promise' is not assignable to type 'ElementType<{ title: string; }>'. +tests/cases/compiler/jsxElementType.tsx(49,1): error TS2322: Type '({ title }: { title: string; }) => Promise' is not assignable to type 'NewReactJSXElementConstructor<{ title: string; }>'. Type '({ title }: { title: string; }) => Promise' is not assignable to type '(props: { title: string; }) => React18ReactNode'. Type 'Promise' is not assignable to type 'React18ReactNode'. tests/cases/compiler/jsxElementType.tsx(50,2): error TS2741: Property 'title' is missing in type '{}' but required in type '{ title: string; }'. tests/cases/compiler/jsxElementType.tsx(50,2): error TS2786: 'RenderPromise' cannot be used as a JSX component. Its instance type '({ title }: { title: string; }) => Promise' is not a valid JSX element. - Type '({ title }: { title: string; }) => Promise' is not comparable to type '(props: Props) => React18ReactNode'. - Type 'Promise' is not comparable to type 'React18ReactNode'. + Type '({ title }: { title: string; }) => Promise' is not assignable to type '(props: any) => React18ReactNode'. + Type 'Promise' is not assignable to type 'React18ReactNode'. tests/cases/compiler/jsxElementType.tsx(51,2): error TS2786: 'RenderPromise' cannot be used as a JSX component. Its instance type '({ title }: { title: string; }) => Promise' is not a valid JSX element. tests/cases/compiler/jsxElementType.tsx(52,2): error TS2786: 'RenderPromise' cannot be used as a JSX component. Its instance type '({ title }: { title: string; }) => Promise' is not a valid JSX element. tests/cases/compiler/jsxElementType.tsx(52,16): error TS2322: Type '{ excessProp: true; }' is not assignable to type 'IntrinsicAttributes & { title: string; }'. Property 'excessProp' does not exist on type 'IntrinsicAttributes & { title: string; }'. +tests/cases/compiler/jsxElementType.tsx(64,2): error TS2786: 'ReactNativeFlatList' cannot be used as a JSX component. + Its instance type '(props: {}, ref: ForwardedRef) => null' is not a valid JSX element. + Type '(props: {}, ref: ForwardedRef) => null' is not assignable to type '(props: any) => React18ReactNode'. -==== tests/cases/compiler/jsxElementType.tsx (12 errors) ==== +==== tests/cases/compiler/jsxElementType.tsx (13 errors) ==== /// import * as React from "react"; @@ -45,11 +48,11 @@ tests/cases/compiler/jsxElementType.tsx(52,16): error TS2322: Type '{ excessProp declare global { namespace JSX { - type ElementType = string | NewReactJSXElementConstructor; + type ElementType = string | NewReactJSXElementConstructor; } } - let Component: JSX.ElementType<{ title: string }>; + let Component: NewReactJSXElementConstructor<{ title: string }>; const RenderString = ({ title }: { title: string }) => title; Component = RenderString; @@ -92,7 +95,7 @@ tests/cases/compiler/jsxElementType.tsx(52,16): error TS2322: Type '{ excessProp const RenderPromise = async ({ title }: { title: string }) => "react"; Component = RenderPromise; ~~~~~~~~~ -!!! error TS2322: Type '({ title }: { title: string; }) => Promise' is not assignable to type 'ElementType<{ title: string; }>'. +!!! error TS2322: Type '({ title }: { title: string; }) => Promise' is not assignable to type 'NewReactJSXElementConstructor<{ title: string; }>'. !!! error TS2322: Type '({ title }: { title: string; }) => Promise' is not assignable to type '(props: { title: string; }) => React18ReactNode'. !!! error TS2322: Type 'Promise' is not assignable to type 'React18ReactNode'. ; @@ -102,8 +105,8 @@ tests/cases/compiler/jsxElementType.tsx(52,16): error TS2322: Type '{ excessProp ~~~~~~~~~~~~~ !!! error TS2786: 'RenderPromise' cannot be used as a JSX component. !!! error TS2786: Its instance type '({ title }: { title: string; }) => Promise' is not a valid JSX element. -!!! error TS2786: Type '({ title }: { title: string; }) => Promise' is not comparable to type '(props: Props) => React18ReactNode'. -!!! error TS2786: Type 'Promise' is not comparable to type 'React18ReactNode'. +!!! error TS2786: Type '({ title }: { title: string; }) => Promise' is not assignable to type '(props: any) => React18ReactNode'. +!!! error TS2786: Type 'Promise' is not assignable to type 'React18ReactNode'. ; ~~~~~~~~~~~~~ !!! error TS2786: 'RenderPromise' cannot be used as a JSX component. @@ -115,4 +118,19 @@ tests/cases/compiler/jsxElementType.tsx(52,16): error TS2322: Type '{ excessProp ~~~~~~~~~~ !!! error TS2322: Type '{ excessProp: true; }' is not assignable to type 'IntrinsicAttributes & { title: string; }'. !!! error TS2322: Property 'excessProp' does not exist on type 'IntrinsicAttributes & { title: string; }'. - \ No newline at end of file + + // Highlighting various ecosystem compat issues + // react-native-gesture-handler + // https://github.com/software-mansion/react-native-gesture-handler/blob/79017e5e7cc2e82e6467851f870920ff836ee04f/src/components/GestureComponents.tsx#L139-L146 + interface ReactNativeFlatListProps {} + function ReactNativeFlatList( + props: {}, + ref: React.ForwardedRef + ) { + return null; + } + ; + ~~~~~~~~~~~~~~~~~~~ +!!! error TS2786: 'ReactNativeFlatList' cannot be used as a JSX component. +!!! error TS2786: Its instance type '(props: {}, ref: ForwardedRef) => null' is not a valid JSX element. +!!! error TS2786: Type '(props: {}, ref: ForwardedRef) => null' is not assignable to type '(props: any) => React18ReactNode'. \ No newline at end of file diff --git a/tests/baselines/reference/jsxElementType.js b/tests/baselines/reference/jsxElementType.js index eacc87ddc094c..6edee062b5fbc 100644 --- a/tests/baselines/reference/jsxElementType.js +++ b/tests/baselines/reference/jsxElementType.js @@ -20,11 +20,11 @@ type NewReactJSXElementConstructor

= declare global { namespace JSX { - type ElementType = string | NewReactJSXElementConstructor; + type ElementType = string | NewReactJSXElementConstructor; } } -let Component: JSX.ElementType<{ title: string }>; +let Component: NewReactJSXElementConstructor<{ title: string }>; const RenderString = ({ title }: { title: string }) => title; Component = RenderString; @@ -51,7 +51,18 @@ Component = RenderPromise; ; ; ; - + +// Highlighting various ecosystem compat issues +// react-native-gesture-handler +// https://github.com/software-mansion/react-native-gesture-handler/blob/79017e5e7cc2e82e6467851f870920ff836ee04f/src/components/GestureComponents.tsx#L139-L146 +interface ReactNativeFlatListProps {} +function ReactNativeFlatList( + props: {}, + ref: React.ForwardedRef +) { + return null; +} +; //// [jsxElementType.js] "use strict"; @@ -131,3 +142,7 @@ Component = RenderPromise; React.createElement(RenderPromise, null); React.createElement(RenderPromise, { title: "react" }); React.createElement(RenderPromise, { excessProp: true }); +function ReactNativeFlatList(props, ref) { + return null; +} +React.createElement(ReactNativeFlatList, null); diff --git a/tests/baselines/reference/jsxElementType.symbols b/tests/baselines/reference/jsxElementType.symbols index 531230d409ad4..929d0940909df 100644 --- a/tests/baselines/reference/jsxElementType.symbols +++ b/tests/baselines/reference/jsxElementType.symbols @@ -51,19 +51,16 @@ declare global { namespace JSX { >JSX : Symbol(JSX, Decl(react16.d.ts, 2493, 12), Decl(jsxElementType.tsx, 19, 16)) - type ElementType = string | NewReactJSXElementConstructor; + type ElementType = string | NewReactJSXElementConstructor; >ElementType : Symbol(ElementType, Decl(jsxElementType.tsx, 20, 17)) ->Props : Symbol(Props, Decl(jsxElementType.tsx, 21, 21)) >NewReactJSXElementConstructor : Symbol(NewReactJSXElementConstructor, Decl(jsxElementType.tsx, 12, 14)) ->Props : Symbol(Props, Decl(jsxElementType.tsx, 21, 21)) } } -let Component: JSX.ElementType<{ title: string }>; +let Component: NewReactJSXElementConstructor<{ title: string }>; >Component : Symbol(Component, Decl(jsxElementType.tsx, 25, 3)) ->JSX : Symbol(JSX, Decl(react16.d.ts, 2493, 12), Decl(jsxElementType.tsx, 19, 16)) ->ElementType : Symbol(JSX.ElementType, Decl(jsxElementType.tsx, 20, 17)) ->title : Symbol(title, Decl(jsxElementType.tsx, 25, 32)) +>NewReactJSXElementConstructor : Symbol(NewReactJSXElementConstructor, Decl(jsxElementType.tsx, 12, 14)) +>title : Symbol(title, Decl(jsxElementType.tsx, 25, 46)) const RenderString = ({ title }: { title: string }) => title; >RenderString : Symbol(RenderString, Decl(jsxElementType.tsx, 27, 5)) @@ -152,3 +149,28 @@ Component = RenderPromise; >RenderPromise : Symbol(RenderPromise, Decl(jsxElementType.tsx, 47, 5)) >excessProp : Symbol(excessProp, Decl(jsxElementType.tsx, 51, 14)) +// Highlighting various ecosystem compat issues +// react-native-gesture-handler +// https://github.com/software-mansion/react-native-gesture-handler/blob/79017e5e7cc2e82e6467851f870920ff836ee04f/src/components/GestureComponents.tsx#L139-L146 +interface ReactNativeFlatListProps {} +>ReactNativeFlatListProps : Symbol(ReactNativeFlatListProps, Decl(jsxElementType.tsx, 51, 29)) +>Item : Symbol(Item, Decl(jsxElementType.tsx, 56, 35)) + +function ReactNativeFlatList( +>ReactNativeFlatList : Symbol(ReactNativeFlatList, Decl(jsxElementType.tsx, 56, 43)) + + props: {}, +>props : Symbol(props, Decl(jsxElementType.tsx, 57, 29)) + + ref: React.ForwardedRef +>ref : Symbol(ref, Decl(jsxElementType.tsx, 58, 12)) +>React : Symbol(React, Decl(jsxElementType.tsx, 1, 6)) +>ForwardedRef : Symbol(React.ForwardedRef, Decl(react16.d.ts, 2355, 9)) +>ReactNativeFlatList : Symbol(ReactNativeFlatList, Decl(jsxElementType.tsx, 56, 43)) + +) { + return null; +} +; +>ReactNativeFlatList : Symbol(ReactNativeFlatList, Decl(jsxElementType.tsx, 56, 43)) + diff --git a/tests/baselines/reference/jsxElementType.types b/tests/baselines/reference/jsxElementType.types index e84b26bde68ea..0e95d3f2bd4db 100644 --- a/tests/baselines/reference/jsxElementType.types +++ b/tests/baselines/reference/jsxElementType.types @@ -39,14 +39,13 @@ declare global { >global : any namespace JSX { - type ElementType = string | NewReactJSXElementConstructor; ->ElementType : ElementType + type ElementType = string | NewReactJSXElementConstructor; +>ElementType : string | NewReactJSXElementConstructor } } -let Component: JSX.ElementType<{ title: string }>; ->Component : JSX.ElementType<{ title: string; }> ->JSX : any +let Component: NewReactJSXElementConstructor<{ title: string }>; +>Component : NewReactJSXElementConstructor<{ title: string; }> >title : string const RenderString = ({ title }: { title: string }) => title; @@ -58,7 +57,7 @@ const RenderString = ({ title }: { title: string }) => title; Component = RenderString; >Component = RenderString : ({ title }: { title: string; }) => string ->Component : JSX.ElementType<{ title: string; }> +>Component : NewReactJSXElementConstructor<{ title: string; }> >RenderString : ({ title }: { title: string; }) => string ; @@ -86,7 +85,7 @@ const RenderNumber = ({ title }: { title: string }) => title.length; Component = RenderNumber; >Component = RenderNumber : ({ title }: { title: string; }) => number ->Component : JSX.ElementType<{ title: string; }> +>Component : NewReactJSXElementConstructor<{ title: string; }> >RenderNumber : ({ title }: { title: string; }) => number ; @@ -113,7 +112,7 @@ const RenderArray = ({ title }: { title: string }) => [title]; Component = RenderArray; >Component = RenderArray : ({ title }: { title: string; }) => string[] ->Component : JSX.ElementType<{ title: string; }> +>Component : NewReactJSXElementConstructor<{ title: string; }> >RenderArray : ({ title }: { title: string; }) => string[] ; @@ -141,7 +140,7 @@ const RenderPromise = async ({ title }: { title: string }) => "react"; Component = RenderPromise; >Component = RenderPromise : ({ title }: { title: string; }) => Promise ->Component : JSX.ElementType<{ title: string; }> +>Component : NewReactJSXElementConstructor<{ title: string; }> >RenderPromise : ({ title }: { title: string; }) => Promise ; @@ -158,3 +157,26 @@ Component = RenderPromise; >RenderPromise : ({ title }: { title: string; }) => Promise >excessProp : true +// Highlighting various ecosystem compat issues +// react-native-gesture-handler +// https://github.com/software-mansion/react-native-gesture-handler/blob/79017e5e7cc2e82e6467851f870920ff836ee04f/src/components/GestureComponents.tsx#L139-L146 +interface ReactNativeFlatListProps {} +function ReactNativeFlatList( +>ReactNativeFlatList : (props: {}, ref: React.ForwardedRef) => null + + props: {}, +>props : {} + + ref: React.ForwardedRef +>ref : React.ForwardedRef<(props: {}, ref: React.ForwardedRef) => null> +>React : any +>ReactNativeFlatList : (props: {}, ref: React.ForwardedRef) => null + +) { + return null; +>null : null +} +; +> : JSX.Element +>ReactNativeFlatList : (props: {}, ref: React.ForwardedRef) => null + diff --git a/tests/cases/compiler/jsxElementType.tsx b/tests/cases/compiler/jsxElementType.tsx index d56a751a3b500..61e4ed438c847 100644 --- a/tests/cases/compiler/jsxElementType.tsx +++ b/tests/cases/compiler/jsxElementType.tsx @@ -21,11 +21,11 @@ type NewReactJSXElementConstructor

= declare global { namespace JSX { - type ElementType = string | NewReactJSXElementConstructor; + type ElementType = string | NewReactJSXElementConstructor; } } -let Component: JSX.ElementType<{ title: string }>; +let Component: NewReactJSXElementConstructor<{ title: string }>; const RenderString = ({ title }: { title: string }) => title; Component = RenderString; @@ -52,3 +52,15 @@ Component = RenderPromise; ; ; ; + +// Highlighting various ecosystem compat issues +// react-native-gesture-handler +// https://github.com/software-mansion/react-native-gesture-handler/blob/79017e5e7cc2e82e6467851f870920ff836ee04f/src/components/GestureComponents.tsx#L139-L146 +interface ReactNativeFlatListProps {} +function ReactNativeFlatList( + props: {}, + ref: React.ForwardedRef +) { + return null; +} +; \ No newline at end of file From 8a3307e844fa441759cb56167e54b26ae469e7eb Mon Sep 17 00:00:00 2001 From: Sebastian Silbermann Date: Tue, 14 Feb 2023 16:14:40 +0100 Subject: [PATCH 05/19] (failing) test for host components --- src/compiler/checker.ts | 2 +- .../reference/jsxElementType.errors.txt | 49 ++++--- tests/baselines/reference/jsxElementType.js | 10 ++ .../reference/jsxElementType.symbols | 121 ++++++++++-------- .../baselines/reference/jsxElementType.types | 16 +++ tests/cases/compiler/jsxElementType.tsx | 7 + 6 files changed, 134 insertions(+), 71 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 27ec4e1da7e4b..76a83cd06b2bd 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -30521,7 +30521,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { checkDeprecatedSignature(sig, node); const elementTypeConstraint = getJsxElementTypeTypeAt(jsxOpeningLikeNode); - if (elementTypeConstraint !== undefined) { + if (false) { const tagType = getApparentType(checkExpression(jsxOpeningLikeNode.tagName)); // TODO: error message checkTypeRelatedTo(tagType, elementTypeConstraint, assignableRelation, jsxOpeningLikeNode.tagName, Diagnostics.Its_instance_type_0_is_not_a_valid_JSX_element, () => { diff --git a/tests/baselines/reference/jsxElementType.errors.txt b/tests/baselines/reference/jsxElementType.errors.txt index 43c52457316b6..76adc4456ae49 100644 --- a/tests/baselines/reference/jsxElementType.errors.txt +++ b/tests/baselines/reference/jsxElementType.errors.txt @@ -1,32 +1,34 @@ -tests/cases/compiler/jsxElementType.tsx(30,2): error TS2741: Property 'title' is missing in type '{}' but required in type '{ title: string; }'. -tests/cases/compiler/jsxElementType.tsx(32,15): error TS2322: Type '{ excessProp: true; }' is not assignable to type 'IntrinsicAttributes & { title: string; }'. +tests/cases/compiler/jsxElementType.tsx(33,2): error TS2741: Property 'title' is missing in type '{}' but required in type '{ title: string; }'. +tests/cases/compiler/jsxElementType.tsx(35,15): error TS2322: Type '{ excessProp: true; }' is not assignable to type 'IntrinsicAttributes & { title: string; }'. Property 'excessProp' does not exist on type 'IntrinsicAttributes & { title: string; }'. -tests/cases/compiler/jsxElementType.tsx(36,2): error TS2741: Property 'title' is missing in type '{}' but required in type '{ title: string; }'. -tests/cases/compiler/jsxElementType.tsx(38,15): error TS2322: Type '{ excessProp: true; }' is not assignable to type 'IntrinsicAttributes & { title: string; }'. +tests/cases/compiler/jsxElementType.tsx(39,2): error TS2741: Property 'title' is missing in type '{}' but required in type '{ title: string; }'. +tests/cases/compiler/jsxElementType.tsx(41,15): error TS2322: Type '{ excessProp: true; }' is not assignable to type 'IntrinsicAttributes & { title: string; }'. Property 'excessProp' does not exist on type 'IntrinsicAttributes & { title: string; }'. -tests/cases/compiler/jsxElementType.tsx(42,2): error TS2741: Property 'title' is missing in type '{}' but required in type '{ title: string; }'. -tests/cases/compiler/jsxElementType.tsx(44,14): error TS2322: Type '{ excessProp: true; }' is not assignable to type 'IntrinsicAttributes & { title: string; }'. +tests/cases/compiler/jsxElementType.tsx(45,2): error TS2741: Property 'title' is missing in type '{}' but required in type '{ title: string; }'. +tests/cases/compiler/jsxElementType.tsx(47,14): error TS2322: Type '{ excessProp: true; }' is not assignable to type 'IntrinsicAttributes & { title: string; }'. Property 'excessProp' does not exist on type 'IntrinsicAttributes & { title: string; }'. -tests/cases/compiler/jsxElementType.tsx(49,1): error TS2322: Type '({ title }: { title: string; }) => Promise' is not assignable to type 'NewReactJSXElementConstructor<{ title: string; }>'. +tests/cases/compiler/jsxElementType.tsx(52,1): error TS2322: Type '({ title }: { title: string; }) => Promise' is not assignable to type 'NewReactJSXElementConstructor<{ title: string; }>'. Type '({ title }: { title: string; }) => Promise' is not assignable to type '(props: { title: string; }) => React18ReactNode'. Type 'Promise' is not assignable to type 'React18ReactNode'. -tests/cases/compiler/jsxElementType.tsx(50,2): error TS2741: Property 'title' is missing in type '{}' but required in type '{ title: string; }'. -tests/cases/compiler/jsxElementType.tsx(50,2): error TS2786: 'RenderPromise' cannot be used as a JSX component. +tests/cases/compiler/jsxElementType.tsx(53,2): error TS2741: Property 'title' is missing in type '{}' but required in type '{ title: string; }'. +tests/cases/compiler/jsxElementType.tsx(53,2): error TS2786: 'RenderPromise' cannot be used as a JSX component. Its instance type '({ title }: { title: string; }) => Promise' is not a valid JSX element. Type '({ title }: { title: string; }) => Promise' is not assignable to type '(props: any) => React18ReactNode'. Type 'Promise' is not assignable to type 'React18ReactNode'. -tests/cases/compiler/jsxElementType.tsx(51,2): error TS2786: 'RenderPromise' cannot be used as a JSX component. +tests/cases/compiler/jsxElementType.tsx(54,2): error TS2786: 'RenderPromise' cannot be used as a JSX component. Its instance type '({ title }: { title: string; }) => Promise' is not a valid JSX element. -tests/cases/compiler/jsxElementType.tsx(52,2): error TS2786: 'RenderPromise' cannot be used as a JSX component. +tests/cases/compiler/jsxElementType.tsx(55,2): error TS2786: 'RenderPromise' cannot be used as a JSX component. Its instance type '({ title }: { title: string; }) => Promise' is not a valid JSX element. -tests/cases/compiler/jsxElementType.tsx(52,16): error TS2322: Type '{ excessProp: true; }' is not assignable to type 'IntrinsicAttributes & { title: string; }'. +tests/cases/compiler/jsxElementType.tsx(55,16): error TS2322: Type '{ excessProp: true; }' is not assignable to type 'IntrinsicAttributes & { title: string; }'. Property 'excessProp' does not exist on type 'IntrinsicAttributes & { title: string; }'. -tests/cases/compiler/jsxElementType.tsx(64,2): error TS2786: 'ReactNativeFlatList' cannot be used as a JSX component. +tests/cases/compiler/jsxElementType.tsx(58,2): error TS2304: Cannot find name 'div'. +tests/cases/compiler/jsxElementType.tsx(59,2): error TS2304: Cannot find name 'my-web-component'. +tests/cases/compiler/jsxElementType.tsx(71,2): error TS2786: 'ReactNativeFlatList' cannot be used as a JSX component. Its instance type '(props: {}, ref: ForwardedRef) => null' is not a valid JSX element. Type '(props: {}, ref: ForwardedRef) => null' is not assignable to type '(props: any) => React18ReactNode'. -==== tests/cases/compiler/jsxElementType.tsx (13 errors) ==== +==== tests/cases/compiler/jsxElementType.tsx (15 errors) ==== /// import * as React from "react"; @@ -49,6 +51,9 @@ tests/cases/compiler/jsxElementType.tsx(64,2): error TS2786: 'ReactNativeFlatLis declare global { namespace JSX { type ElementType = string | NewReactJSXElementConstructor; + interface IntrinsicElements { + ['my-web-component']: React.DOMAttributes; + } } } @@ -59,7 +64,7 @@ tests/cases/compiler/jsxElementType.tsx(64,2): error TS2786: 'ReactNativeFlatLis ; ~~~~~~~~~~~~ !!! error TS2741: Property 'title' is missing in type '{}' but required in type '{ title: string; }'. -!!! related TS2728 tests/cases/compiler/jsxElementType.tsx:28:36: 'title' is declared here. +!!! related TS2728 tests/cases/compiler/jsxElementType.tsx:31:36: 'title' is declared here. ; ; ~~~~~~~~~~ @@ -71,7 +76,7 @@ tests/cases/compiler/jsxElementType.tsx(64,2): error TS2786: 'ReactNativeFlatLis ; ~~~~~~~~~~~~ !!! error TS2741: Property 'title' is missing in type '{}' but required in type '{ title: string; }'. -!!! related TS2728 tests/cases/compiler/jsxElementType.tsx:34:36: 'title' is declared here. +!!! related TS2728 tests/cases/compiler/jsxElementType.tsx:37:36: 'title' is declared here. ; ; ~~~~~~~~~~ @@ -83,7 +88,7 @@ tests/cases/compiler/jsxElementType.tsx(64,2): error TS2786: 'ReactNativeFlatLis ; ~~~~~~~~~~~ !!! error TS2741: Property 'title' is missing in type '{}' but required in type '{ title: string; }'. -!!! related TS2728 tests/cases/compiler/jsxElementType.tsx:40:35: 'title' is declared here. +!!! related TS2728 tests/cases/compiler/jsxElementType.tsx:43:35: 'title' is declared here. ; ; ~~~~~~~~~~ @@ -101,7 +106,7 @@ tests/cases/compiler/jsxElementType.tsx(64,2): error TS2786: 'ReactNativeFlatLis ; ~~~~~~~~~~~~~ !!! error TS2741: Property 'title' is missing in type '{}' but required in type '{ title: string; }'. -!!! related TS2728 tests/cases/compiler/jsxElementType.tsx:48:43: 'title' is declared here. +!!! related TS2728 tests/cases/compiler/jsxElementType.tsx:51:43: 'title' is declared here. ~~~~~~~~~~~~~ !!! error TS2786: 'RenderPromise' cannot be used as a JSX component. !!! error TS2786: Its instance type '({ title }: { title: string; }) => Promise' is not a valid JSX element. @@ -119,6 +124,14 @@ tests/cases/compiler/jsxElementType.tsx(64,2): error TS2786: 'ReactNativeFlatLis !!! error TS2322: Type '{ excessProp: true; }' is not assignable to type 'IntrinsicAttributes & { title: string; }'. !!! error TS2322: Property 'excessProp' does not exist on type 'IntrinsicAttributes & { title: string; }'. + // Host element types still work +

; + ~~~ +!!! error TS2304: Cannot find name 'div'. + ; + ~~~~~~~~~~~~~~~~ +!!! error TS2304: Cannot find name 'my-web-component'. + // Highlighting various ecosystem compat issues // react-native-gesture-handler // https://github.com/software-mansion/react-native-gesture-handler/blob/79017e5e7cc2e82e6467851f870920ff836ee04f/src/components/GestureComponents.tsx#L139-L146 diff --git a/tests/baselines/reference/jsxElementType.js b/tests/baselines/reference/jsxElementType.js index 6edee062b5fbc..3582cb0170b1d 100644 --- a/tests/baselines/reference/jsxElementType.js +++ b/tests/baselines/reference/jsxElementType.js @@ -21,6 +21,9 @@ type NewReactJSXElementConstructor

= declare global { namespace JSX { type ElementType = string | NewReactJSXElementConstructor; + interface IntrinsicElements { + ['my-web-component']: React.DOMAttributes; + } } } @@ -52,6 +55,10 @@ Component = RenderPromise; ; ; +// Host element types still work +

; +; + // Highlighting various ecosystem compat issues // react-native-gesture-handler // https://github.com/software-mansion/react-native-gesture-handler/blob/79017e5e7cc2e82e6467851f870920ff836ee04f/src/components/GestureComponents.tsx#L139-L146 @@ -142,6 +149,9 @@ Component = RenderPromise; React.createElement(RenderPromise, null); React.createElement(RenderPromise, { title: "react" }); React.createElement(RenderPromise, { excessProp: true }); +// Host element types still work +React.createElement("div", null); +React.createElement("my-web-component", null); function ReactNativeFlatList(props, ref) { return null; } diff --git a/tests/baselines/reference/jsxElementType.symbols b/tests/baselines/reference/jsxElementType.symbols index 929d0940909df..30dbb6888bdaa 100644 --- a/tests/baselines/reference/jsxElementType.symbols +++ b/tests/baselines/reference/jsxElementType.symbols @@ -54,123 +54,140 @@ declare global { type ElementType = string | NewReactJSXElementConstructor; >ElementType : Symbol(ElementType, Decl(jsxElementType.tsx, 20, 17)) >NewReactJSXElementConstructor : Symbol(NewReactJSXElementConstructor, Decl(jsxElementType.tsx, 12, 14)) + + interface IntrinsicElements { +>IntrinsicElements : Symbol(IntrinsicElements, Decl(react16.d.ts, 2514, 86), Decl(jsxElementType.tsx, 21, 67)) + + ['my-web-component']: React.DOMAttributes; +>['my-web-component'] : Symbol(IntrinsicElements['my-web-component'], Decl(jsxElementType.tsx, 22, 33)) +>'my-web-component' : Symbol(IntrinsicElements['my-web-component'], Decl(jsxElementType.tsx, 22, 33)) +>React : Symbol(React, Decl(jsxElementType.tsx, 1, 6)) +>DOMAttributes : Symbol(React.DOMAttributes, Decl(react16.d.ts, 844, 9)) + } } } let Component: NewReactJSXElementConstructor<{ title: string }>; ->Component : Symbol(Component, Decl(jsxElementType.tsx, 25, 3)) +>Component : Symbol(Component, Decl(jsxElementType.tsx, 28, 3)) >NewReactJSXElementConstructor : Symbol(NewReactJSXElementConstructor, Decl(jsxElementType.tsx, 12, 14)) ->title : Symbol(title, Decl(jsxElementType.tsx, 25, 46)) +>title : Symbol(title, Decl(jsxElementType.tsx, 28, 46)) const RenderString = ({ title }: { title: string }) => title; ->RenderString : Symbol(RenderString, Decl(jsxElementType.tsx, 27, 5)) ->title : Symbol(title, Decl(jsxElementType.tsx, 27, 23)) ->title : Symbol(title, Decl(jsxElementType.tsx, 27, 34)) ->title : Symbol(title, Decl(jsxElementType.tsx, 27, 23)) +>RenderString : Symbol(RenderString, Decl(jsxElementType.tsx, 30, 5)) +>title : Symbol(title, Decl(jsxElementType.tsx, 30, 23)) +>title : Symbol(title, Decl(jsxElementType.tsx, 30, 34)) +>title : Symbol(title, Decl(jsxElementType.tsx, 30, 23)) Component = RenderString; ->Component : Symbol(Component, Decl(jsxElementType.tsx, 25, 3)) ->RenderString : Symbol(RenderString, Decl(jsxElementType.tsx, 27, 5)) +>Component : Symbol(Component, Decl(jsxElementType.tsx, 28, 3)) +>RenderString : Symbol(RenderString, Decl(jsxElementType.tsx, 30, 5)) ; ->RenderString : Symbol(RenderString, Decl(jsxElementType.tsx, 27, 5)) +>RenderString : Symbol(RenderString, Decl(jsxElementType.tsx, 30, 5)) ; ->RenderString : Symbol(RenderString, Decl(jsxElementType.tsx, 27, 5)) ->title : Symbol(title, Decl(jsxElementType.tsx, 30, 13)) +>RenderString : Symbol(RenderString, Decl(jsxElementType.tsx, 30, 5)) +>title : Symbol(title, Decl(jsxElementType.tsx, 33, 13)) ; ->RenderString : Symbol(RenderString, Decl(jsxElementType.tsx, 27, 5)) ->excessProp : Symbol(excessProp, Decl(jsxElementType.tsx, 31, 13)) +>RenderString : Symbol(RenderString, Decl(jsxElementType.tsx, 30, 5)) +>excessProp : Symbol(excessProp, Decl(jsxElementType.tsx, 34, 13)) const RenderNumber = ({ title }: { title: string }) => title.length; ->RenderNumber : Symbol(RenderNumber, Decl(jsxElementType.tsx, 33, 5)) ->title : Symbol(title, Decl(jsxElementType.tsx, 33, 23)) ->title : Symbol(title, Decl(jsxElementType.tsx, 33, 34)) +>RenderNumber : Symbol(RenderNumber, Decl(jsxElementType.tsx, 36, 5)) +>title : Symbol(title, Decl(jsxElementType.tsx, 36, 23)) +>title : Symbol(title, Decl(jsxElementType.tsx, 36, 34)) >title.length : Symbol(String.length, Decl(lib.es5.d.ts, --, --)) ->title : Symbol(title, Decl(jsxElementType.tsx, 33, 23)) +>title : Symbol(title, Decl(jsxElementType.tsx, 36, 23)) >length : Symbol(String.length, Decl(lib.es5.d.ts, --, --)) Component = RenderNumber; ->Component : Symbol(Component, Decl(jsxElementType.tsx, 25, 3)) ->RenderNumber : Symbol(RenderNumber, Decl(jsxElementType.tsx, 33, 5)) +>Component : Symbol(Component, Decl(jsxElementType.tsx, 28, 3)) +>RenderNumber : Symbol(RenderNumber, Decl(jsxElementType.tsx, 36, 5)) ; ->RenderNumber : Symbol(RenderNumber, Decl(jsxElementType.tsx, 33, 5)) +>RenderNumber : Symbol(RenderNumber, Decl(jsxElementType.tsx, 36, 5)) ; ->RenderNumber : Symbol(RenderNumber, Decl(jsxElementType.tsx, 33, 5)) ->title : Symbol(title, Decl(jsxElementType.tsx, 36, 13)) +>RenderNumber : Symbol(RenderNumber, Decl(jsxElementType.tsx, 36, 5)) +>title : Symbol(title, Decl(jsxElementType.tsx, 39, 13)) ; ->RenderNumber : Symbol(RenderNumber, Decl(jsxElementType.tsx, 33, 5)) ->excessProp : Symbol(excessProp, Decl(jsxElementType.tsx, 37, 13)) +>RenderNumber : Symbol(RenderNumber, Decl(jsxElementType.tsx, 36, 5)) +>excessProp : Symbol(excessProp, Decl(jsxElementType.tsx, 40, 13)) const RenderArray = ({ title }: { title: string }) => [title]; ->RenderArray : Symbol(RenderArray, Decl(jsxElementType.tsx, 39, 5)) ->title : Symbol(title, Decl(jsxElementType.tsx, 39, 22)) ->title : Symbol(title, Decl(jsxElementType.tsx, 39, 33)) ->title : Symbol(title, Decl(jsxElementType.tsx, 39, 22)) +>RenderArray : Symbol(RenderArray, Decl(jsxElementType.tsx, 42, 5)) +>title : Symbol(title, Decl(jsxElementType.tsx, 42, 22)) +>title : Symbol(title, Decl(jsxElementType.tsx, 42, 33)) +>title : Symbol(title, Decl(jsxElementType.tsx, 42, 22)) Component = RenderArray; ->Component : Symbol(Component, Decl(jsxElementType.tsx, 25, 3)) ->RenderArray : Symbol(RenderArray, Decl(jsxElementType.tsx, 39, 5)) +>Component : Symbol(Component, Decl(jsxElementType.tsx, 28, 3)) +>RenderArray : Symbol(RenderArray, Decl(jsxElementType.tsx, 42, 5)) ; ->RenderArray : Symbol(RenderArray, Decl(jsxElementType.tsx, 39, 5)) +>RenderArray : Symbol(RenderArray, Decl(jsxElementType.tsx, 42, 5)) ; ->RenderArray : Symbol(RenderArray, Decl(jsxElementType.tsx, 39, 5)) ->title : Symbol(title, Decl(jsxElementType.tsx, 42, 12)) +>RenderArray : Symbol(RenderArray, Decl(jsxElementType.tsx, 42, 5)) +>title : Symbol(title, Decl(jsxElementType.tsx, 45, 12)) ; ->RenderArray : Symbol(RenderArray, Decl(jsxElementType.tsx, 39, 5)) ->excessProp : Symbol(excessProp, Decl(jsxElementType.tsx, 43, 12)) +>RenderArray : Symbol(RenderArray, Decl(jsxElementType.tsx, 42, 5)) +>excessProp : Symbol(excessProp, Decl(jsxElementType.tsx, 46, 12)) // Future ReactNode can be Promises. // But they should be rejected in React 18.0. const RenderPromise = async ({ title }: { title: string }) => "react"; ->RenderPromise : Symbol(RenderPromise, Decl(jsxElementType.tsx, 47, 5)) ->title : Symbol(title, Decl(jsxElementType.tsx, 47, 30)) ->title : Symbol(title, Decl(jsxElementType.tsx, 47, 41)) +>RenderPromise : Symbol(RenderPromise, Decl(jsxElementType.tsx, 50, 5)) +>title : Symbol(title, Decl(jsxElementType.tsx, 50, 30)) +>title : Symbol(title, Decl(jsxElementType.tsx, 50, 41)) Component = RenderPromise; ->Component : Symbol(Component, Decl(jsxElementType.tsx, 25, 3)) ->RenderPromise : Symbol(RenderPromise, Decl(jsxElementType.tsx, 47, 5)) +>Component : Symbol(Component, Decl(jsxElementType.tsx, 28, 3)) +>RenderPromise : Symbol(RenderPromise, Decl(jsxElementType.tsx, 50, 5)) ; ->RenderPromise : Symbol(RenderPromise, Decl(jsxElementType.tsx, 47, 5)) +>RenderPromise : Symbol(RenderPromise, Decl(jsxElementType.tsx, 50, 5)) ; ->RenderPromise : Symbol(RenderPromise, Decl(jsxElementType.tsx, 47, 5)) ->title : Symbol(title, Decl(jsxElementType.tsx, 50, 14)) +>RenderPromise : Symbol(RenderPromise, Decl(jsxElementType.tsx, 50, 5)) +>title : Symbol(title, Decl(jsxElementType.tsx, 53, 14)) ; ->RenderPromise : Symbol(RenderPromise, Decl(jsxElementType.tsx, 47, 5)) ->excessProp : Symbol(excessProp, Decl(jsxElementType.tsx, 51, 14)) +>RenderPromise : Symbol(RenderPromise, Decl(jsxElementType.tsx, 50, 5)) +>excessProp : Symbol(excessProp, Decl(jsxElementType.tsx, 54, 14)) + +// Host element types still work +
; +>div : Symbol(JSX.IntrinsicElements.div, Decl(react16.d.ts, 2546, 114)) + +; +>my-web-component : Symbol(JSX.IntrinsicElements['my-web-component'], Decl(jsxElementType.tsx, 22, 33)) // Highlighting various ecosystem compat issues // react-native-gesture-handler // https://github.com/software-mansion/react-native-gesture-handler/blob/79017e5e7cc2e82e6467851f870920ff836ee04f/src/components/GestureComponents.tsx#L139-L146 interface ReactNativeFlatListProps {} ->ReactNativeFlatListProps : Symbol(ReactNativeFlatListProps, Decl(jsxElementType.tsx, 51, 29)) ->Item : Symbol(Item, Decl(jsxElementType.tsx, 56, 35)) +>ReactNativeFlatListProps : Symbol(ReactNativeFlatListProps, Decl(jsxElementType.tsx, 58, 21)) +>Item : Symbol(Item, Decl(jsxElementType.tsx, 63, 35)) function ReactNativeFlatList( ->ReactNativeFlatList : Symbol(ReactNativeFlatList, Decl(jsxElementType.tsx, 56, 43)) +>ReactNativeFlatList : Symbol(ReactNativeFlatList, Decl(jsxElementType.tsx, 63, 43)) props: {}, ->props : Symbol(props, Decl(jsxElementType.tsx, 57, 29)) +>props : Symbol(props, Decl(jsxElementType.tsx, 64, 29)) ref: React.ForwardedRef ->ref : Symbol(ref, Decl(jsxElementType.tsx, 58, 12)) +>ref : Symbol(ref, Decl(jsxElementType.tsx, 65, 12)) >React : Symbol(React, Decl(jsxElementType.tsx, 1, 6)) >ForwardedRef : Symbol(React.ForwardedRef, Decl(react16.d.ts, 2355, 9)) ->ReactNativeFlatList : Symbol(ReactNativeFlatList, Decl(jsxElementType.tsx, 56, 43)) +>ReactNativeFlatList : Symbol(ReactNativeFlatList, Decl(jsxElementType.tsx, 63, 43)) ) { return null; } ; ->ReactNativeFlatList : Symbol(ReactNativeFlatList, Decl(jsxElementType.tsx, 56, 43)) +>ReactNativeFlatList : Symbol(ReactNativeFlatList, Decl(jsxElementType.tsx, 63, 43)) diff --git a/tests/baselines/reference/jsxElementType.types b/tests/baselines/reference/jsxElementType.types index 0e95d3f2bd4db..5f97eb8ab3da3 100644 --- a/tests/baselines/reference/jsxElementType.types +++ b/tests/baselines/reference/jsxElementType.types @@ -41,6 +41,13 @@ declare global { namespace JSX { type ElementType = string | NewReactJSXElementConstructor; >ElementType : string | NewReactJSXElementConstructor + + interface IntrinsicElements { + ['my-web-component']: React.DOMAttributes; +>['my-web-component'] : React.DOMAttributes +>'my-web-component' : "my-web-component" +>React : any + } } } @@ -157,6 +164,15 @@ Component = RenderPromise; >RenderPromise : ({ title }: { title: string; }) => Promise >excessProp : true +// Host element types still work +
; +>
: JSX.Element +>div : any + +; +> : JSX.Element +>my-web-component : any + // Highlighting various ecosystem compat issues // react-native-gesture-handler // https://github.com/software-mansion/react-native-gesture-handler/blob/79017e5e7cc2e82e6467851f870920ff836ee04f/src/components/GestureComponents.tsx#L139-L146 diff --git a/tests/cases/compiler/jsxElementType.tsx b/tests/cases/compiler/jsxElementType.tsx index 61e4ed438c847..7943133e54acb 100644 --- a/tests/cases/compiler/jsxElementType.tsx +++ b/tests/cases/compiler/jsxElementType.tsx @@ -22,6 +22,9 @@ type NewReactJSXElementConstructor

= declare global { namespace JSX { type ElementType = string | NewReactJSXElementConstructor; + interface IntrinsicElements { + ['my-web-component']: React.DOMAttributes; + } } } @@ -53,6 +56,10 @@ Component = RenderPromise; ; ; +// Host element types still work +

; +; + // Highlighting various ecosystem compat issues // react-native-gesture-handler // https://github.com/software-mansion/react-native-gesture-handler/blob/79017e5e7cc2e82e6467851f870920ff836ee04f/src/components/GestureComponents.tsx#L139-L146 From 511180b7d84f89fcc35cab0db01ed164cdc6d389 Mon Sep 17 00:00:00 2001 From: Sebastian Silbermann Date: Tue, 14 Feb 2023 16:14:47 +0100 Subject: [PATCH 06/19] f --- src/compiler/checker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 76a83cd06b2bd..27ec4e1da7e4b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -30521,7 +30521,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { checkDeprecatedSignature(sig, node); const elementTypeConstraint = getJsxElementTypeTypeAt(jsxOpeningLikeNode); - if (false) { + if (elementTypeConstraint !== undefined) { const tagType = getApparentType(checkExpression(jsxOpeningLikeNode.tagName)); // TODO: error message checkTypeRelatedTo(tagType, elementTypeConstraint, assignableRelation, jsxOpeningLikeNode.tagName, Diagnostics.Its_instance_type_0_is_not_a_valid_JSX_element, () => { From c69d4de2acb8680242639db5b0f6c55bd44ae5bc Mon Sep 17 00:00:00 2001 From: Sebastian Silbermann Date: Tue, 14 Feb 2023 16:44:34 +0100 Subject: [PATCH 07/19] Add support for host components called "intrinsic components" in TS --- src/compiler/checker.ts | 5 ++++- tests/baselines/reference/jsxElementType.errors.txt | 8 +------- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 27ec4e1da7e4b..60b9b37f01786 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -30522,7 +30522,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const elementTypeConstraint = getJsxElementTypeTypeAt(jsxOpeningLikeNode); if (elementTypeConstraint !== undefined) { - const tagType = getApparentType(checkExpression(jsxOpeningLikeNode.tagName)); + const tagType = isJsxIntrinsicIdentifier(jsxOpeningLikeNode.tagName) + ? // TODO: Should this be a literal that library authors could potentially check against? + stringType + : getApparentType(checkExpression(jsxOpeningLikeNode.tagName)); // TODO: error message checkTypeRelatedTo(tagType, elementTypeConstraint, assignableRelation, jsxOpeningLikeNode.tagName, Diagnostics.Its_instance_type_0_is_not_a_valid_JSX_element, () => { const componentName = getTextOfNode(jsxOpeningLikeNode.tagName); diff --git a/tests/baselines/reference/jsxElementType.errors.txt b/tests/baselines/reference/jsxElementType.errors.txt index 76adc4456ae49..2fe2bd1207f0d 100644 --- a/tests/baselines/reference/jsxElementType.errors.txt +++ b/tests/baselines/reference/jsxElementType.errors.txt @@ -21,14 +21,12 @@ tests/cases/compiler/jsxElementType.tsx(55,2): error TS2786: 'RenderPromise' can Its instance type '({ title }: { title: string; }) => Promise' is not a valid JSX element. tests/cases/compiler/jsxElementType.tsx(55,16): error TS2322: Type '{ excessProp: true; }' is not assignable to type 'IntrinsicAttributes & { title: string; }'. Property 'excessProp' does not exist on type 'IntrinsicAttributes & { title: string; }'. -tests/cases/compiler/jsxElementType.tsx(58,2): error TS2304: Cannot find name 'div'. -tests/cases/compiler/jsxElementType.tsx(59,2): error TS2304: Cannot find name 'my-web-component'. tests/cases/compiler/jsxElementType.tsx(71,2): error TS2786: 'ReactNativeFlatList' cannot be used as a JSX component. Its instance type '(props: {}, ref: ForwardedRef) => null' is not a valid JSX element. Type '(props: {}, ref: ForwardedRef) => null' is not assignable to type '(props: any) => React18ReactNode'. -==== tests/cases/compiler/jsxElementType.tsx (15 errors) ==== +==== tests/cases/compiler/jsxElementType.tsx (13 errors) ==== /// import * as React from "react"; @@ -126,11 +124,7 @@ tests/cases/compiler/jsxElementType.tsx(71,2): error TS2786: 'ReactNativeFlatLis // Host element types still work
; - ~~~ -!!! error TS2304: Cannot find name 'div'. ; - ~~~~~~~~~~~~~~~~ -!!! error TS2304: Cannot find name 'my-web-component'. // Highlighting various ecosystem compat issues // react-native-gesture-handler From 4e39127bc4cbec1b72be78b57782b49333da4950 Mon Sep 17 00:00:00 2001 From: eps1lon Date: Sun, 2 Apr 2023 09:51:43 +0200 Subject: [PATCH 08/19] Include Promises in React18Node That's where we want to go anyway so we might as well show it. --- .../reference/jsxElementType.errors.txt | 52 ++------ tests/baselines/reference/jsxElementType.js | 9 +- .../reference/jsxElementType.symbols | 112 +++++++++--------- .../baselines/reference/jsxElementType.types | 8 +- tests/cases/compiler/jsxElementType.tsx | 6 +- 5 files changed, 81 insertions(+), 106 deletions(-) diff --git a/tests/baselines/reference/jsxElementType.errors.txt b/tests/baselines/reference/jsxElementType.errors.txt index 2fe2bd1207f0d..4f7e69c9bccb7 100644 --- a/tests/baselines/reference/jsxElementType.errors.txt +++ b/tests/baselines/reference/jsxElementType.errors.txt @@ -1,24 +1,13 @@ -tests/cases/compiler/jsxElementType.tsx(33,2): error TS2741: Property 'title' is missing in type '{}' but required in type '{ title: string; }'. -tests/cases/compiler/jsxElementType.tsx(35,15): error TS2322: Type '{ excessProp: true; }' is not assignable to type 'IntrinsicAttributes & { title: string; }'. +tests/cases/compiler/jsxElementType.tsx(34,2): error TS2741: Property 'title' is missing in type '{}' but required in type '{ title: string; }'. +tests/cases/compiler/jsxElementType.tsx(36,15): error TS2322: Type '{ excessProp: true; }' is not assignable to type 'IntrinsicAttributes & { title: string; }'. Property 'excessProp' does not exist on type 'IntrinsicAttributes & { title: string; }'. -tests/cases/compiler/jsxElementType.tsx(39,2): error TS2741: Property 'title' is missing in type '{}' but required in type '{ title: string; }'. -tests/cases/compiler/jsxElementType.tsx(41,15): error TS2322: Type '{ excessProp: true; }' is not assignable to type 'IntrinsicAttributes & { title: string; }'. +tests/cases/compiler/jsxElementType.tsx(40,2): error TS2741: Property 'title' is missing in type '{}' but required in type '{ title: string; }'. +tests/cases/compiler/jsxElementType.tsx(42,15): error TS2322: Type '{ excessProp: true; }' is not assignable to type 'IntrinsicAttributes & { title: string; }'. Property 'excessProp' does not exist on type 'IntrinsicAttributes & { title: string; }'. -tests/cases/compiler/jsxElementType.tsx(45,2): error TS2741: Property 'title' is missing in type '{}' but required in type '{ title: string; }'. -tests/cases/compiler/jsxElementType.tsx(47,14): error TS2322: Type '{ excessProp: true; }' is not assignable to type 'IntrinsicAttributes & { title: string; }'. +tests/cases/compiler/jsxElementType.tsx(46,2): error TS2741: Property 'title' is missing in type '{}' but required in type '{ title: string; }'. +tests/cases/compiler/jsxElementType.tsx(48,14): error TS2322: Type '{ excessProp: true; }' is not assignable to type 'IntrinsicAttributes & { title: string; }'. Property 'excessProp' does not exist on type 'IntrinsicAttributes & { title: string; }'. -tests/cases/compiler/jsxElementType.tsx(52,1): error TS2322: Type '({ title }: { title: string; }) => Promise' is not assignable to type 'NewReactJSXElementConstructor<{ title: string; }>'. - Type '({ title }: { title: string; }) => Promise' is not assignable to type '(props: { title: string; }) => React18ReactNode'. - Type 'Promise' is not assignable to type 'React18ReactNode'. tests/cases/compiler/jsxElementType.tsx(53,2): error TS2741: Property 'title' is missing in type '{}' but required in type '{ title: string; }'. -tests/cases/compiler/jsxElementType.tsx(53,2): error TS2786: 'RenderPromise' cannot be used as a JSX component. - Its instance type '({ title }: { title: string; }) => Promise' is not a valid JSX element. - Type '({ title }: { title: string; }) => Promise' is not assignable to type '(props: any) => React18ReactNode'. - Type 'Promise' is not assignable to type 'React18ReactNode'. -tests/cases/compiler/jsxElementType.tsx(54,2): error TS2786: 'RenderPromise' cannot be used as a JSX component. - Its instance type '({ title }: { title: string; }) => Promise' is not a valid JSX element. -tests/cases/compiler/jsxElementType.tsx(55,2): error TS2786: 'RenderPromise' cannot be used as a JSX component. - Its instance type '({ title }: { title: string; }) => Promise' is not a valid JSX element. tests/cases/compiler/jsxElementType.tsx(55,16): error TS2322: Type '{ excessProp: true; }' is not assignable to type 'IntrinsicAttributes & { title: string; }'. Property 'excessProp' does not exist on type 'IntrinsicAttributes & { title: string; }'. tests/cases/compiler/jsxElementType.tsx(71,2): error TS2786: 'ReactNativeFlatList' cannot be used as a JSX component. @@ -26,7 +15,7 @@ tests/cases/compiler/jsxElementType.tsx(71,2): error TS2786: 'ReactNativeFlatLis Type '(props: {}, ref: ForwardedRef) => null' is not assignable to type '(props: any) => React18ReactNode'. -==== tests/cases/compiler/jsxElementType.tsx (13 errors) ==== +==== tests/cases/compiler/jsxElementType.tsx (9 errors) ==== /// import * as React from "react"; @@ -39,7 +28,8 @@ tests/cases/compiler/jsxElementType.tsx(71,2): error TS2786: 'ReactNativeFlatLis | React.ReactPortal | boolean | null - | undefined; + | undefined + | Promise; // // React.JSXElementConstructor but it now can return React nodes from function components. type NewReactJSXElementConstructor

= @@ -62,7 +52,7 @@ tests/cases/compiler/jsxElementType.tsx(71,2): error TS2786: 'ReactNativeFlatLis ; ~~~~~~~~~~~~ !!! error TS2741: Property 'title' is missing in type '{}' but required in type '{ title: string; }'. -!!! related TS2728 tests/cases/compiler/jsxElementType.tsx:31:36: 'title' is declared here. +!!! related TS2728 tests/cases/compiler/jsxElementType.tsx:32:36: 'title' is declared here. ; ; ~~~~~~~~~~ @@ -74,7 +64,7 @@ tests/cases/compiler/jsxElementType.tsx(71,2): error TS2786: 'ReactNativeFlatLis ; ~~~~~~~~~~~~ !!! error TS2741: Property 'title' is missing in type '{}' but required in type '{ title: string; }'. -!!! related TS2728 tests/cases/compiler/jsxElementType.tsx:37:36: 'title' is declared here. +!!! related TS2728 tests/cases/compiler/jsxElementType.tsx:38:36: 'title' is declared here. ; ; ~~~~~~~~~~ @@ -86,38 +76,22 @@ tests/cases/compiler/jsxElementType.tsx(71,2): error TS2786: 'ReactNativeFlatLis ; ~~~~~~~~~~~ !!! error TS2741: Property 'title' is missing in type '{}' but required in type '{ title: string; }'. -!!! related TS2728 tests/cases/compiler/jsxElementType.tsx:43:35: 'title' is declared here. +!!! related TS2728 tests/cases/compiler/jsxElementType.tsx:44:35: 'title' is declared here. ; ; ~~~~~~~~~~ !!! error TS2322: Type '{ excessProp: true; }' is not assignable to type 'IntrinsicAttributes & { title: string; }'. !!! error TS2322: Property 'excessProp' does not exist on type 'IntrinsicAttributes & { title: string; }'. - // Future ReactNode can be Promises. - // But they should be rejected in React 18.0. + // React Server Component const RenderPromise = async ({ title }: { title: string }) => "react"; Component = RenderPromise; - ~~~~~~~~~ -!!! error TS2322: Type '({ title }: { title: string; }) => Promise' is not assignable to type 'NewReactJSXElementConstructor<{ title: string; }>'. -!!! error TS2322: Type '({ title }: { title: string; }) => Promise' is not assignable to type '(props: { title: string; }) => React18ReactNode'. -!!! error TS2322: Type 'Promise' is not assignable to type 'React18ReactNode'. ; ~~~~~~~~~~~~~ !!! error TS2741: Property 'title' is missing in type '{}' but required in type '{ title: string; }'. !!! related TS2728 tests/cases/compiler/jsxElementType.tsx:51:43: 'title' is declared here. - ~~~~~~~~~~~~~ -!!! error TS2786: 'RenderPromise' cannot be used as a JSX component. -!!! error TS2786: Its instance type '({ title }: { title: string; }) => Promise' is not a valid JSX element. -!!! error TS2786: Type '({ title }: { title: string; }) => Promise' is not assignable to type '(props: any) => React18ReactNode'. -!!! error TS2786: Type 'Promise' is not assignable to type 'React18ReactNode'. ; - ~~~~~~~~~~~~~ -!!! error TS2786: 'RenderPromise' cannot be used as a JSX component. -!!! error TS2786: Its instance type '({ title }: { title: string; }) => Promise' is not a valid JSX element. ; - ~~~~~~~~~~~~~ -!!! error TS2786: 'RenderPromise' cannot be used as a JSX component. -!!! error TS2786: Its instance type '({ title }: { title: string; }) => Promise' is not a valid JSX element. ~~~~~~~~~~ !!! error TS2322: Type '{ excessProp: true; }' is not assignable to type 'IntrinsicAttributes & { title: string; }'. !!! error TS2322: Property 'excessProp' does not exist on type 'IntrinsicAttributes & { title: string; }'. diff --git a/tests/baselines/reference/jsxElementType.js b/tests/baselines/reference/jsxElementType.js index 3582cb0170b1d..24f018d2b6377 100644 --- a/tests/baselines/reference/jsxElementType.js +++ b/tests/baselines/reference/jsxElementType.js @@ -11,7 +11,8 @@ type React18ReactNode = | React.ReactPortal | boolean | null - | undefined; + | undefined + | Promise; // // React.JSXElementConstructor but it now can return React nodes from function components. type NewReactJSXElementConstructor

= @@ -47,8 +48,7 @@ Component = RenderArray; ; ; -// Future ReactNode can be Promises. -// But they should be rejected in React 18.0. +// React Server Component const RenderPromise = async ({ title }: { title: string }) => "react"; Component = RenderPromise; ; @@ -137,8 +137,7 @@ Component = RenderArray; React.createElement(RenderArray, null); React.createElement(RenderArray, { title: "react" }); React.createElement(RenderArray, { excessProp: true }); -// Future ReactNode can be Promises. -// But they should be rejected in React 18.0. +// React Server Component var RenderPromise = function (_a) { var title = _a.title; return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_b) { diff --git a/tests/baselines/reference/jsxElementType.symbols b/tests/baselines/reference/jsxElementType.symbols index 30dbb6888bdaa..35a951a602c23 100644 --- a/tests/baselines/reference/jsxElementType.symbols +++ b/tests/baselines/reference/jsxElementType.symbols @@ -26,41 +26,44 @@ type React18ReactNode = | boolean | null - | undefined; + | undefined + | Promise; +>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --)) +>React18ReactNode : Symbol(React18ReactNode, Decl(jsxElementType.tsx, 3, 60)) // // React.JSXElementConstructor but it now can return React nodes from function components. type NewReactJSXElementConstructor

= ->NewReactJSXElementConstructor : Symbol(NewReactJSXElementConstructor, Decl(jsxElementType.tsx, 12, 14)) ->P : Symbol(P, Decl(jsxElementType.tsx, 15, 35)) +>NewReactJSXElementConstructor : Symbol(NewReactJSXElementConstructor, Decl(jsxElementType.tsx, 13, 30)) +>P : Symbol(P, Decl(jsxElementType.tsx, 16, 35)) | ((props: P) => React18ReactNode) ->props : Symbol(props, Decl(jsxElementType.tsx, 16, 6)) ->P : Symbol(P, Decl(jsxElementType.tsx, 15, 35)) +>props : Symbol(props, Decl(jsxElementType.tsx, 17, 6)) +>P : Symbol(P, Decl(jsxElementType.tsx, 16, 35)) >React18ReactNode : Symbol(React18ReactNode, Decl(jsxElementType.tsx, 3, 60)) | (new (props: P) => React.Component); ->props : Symbol(props, Decl(jsxElementType.tsx, 17, 10)) ->P : Symbol(P, Decl(jsxElementType.tsx, 15, 35)) +>props : Symbol(props, Decl(jsxElementType.tsx, 18, 10)) +>P : Symbol(P, Decl(jsxElementType.tsx, 16, 35)) >React : Symbol(React, Decl(jsxElementType.tsx, 1, 6)) >Component : Symbol(React.Component, Decl(react16.d.ts, 345, 54), Decl(react16.d.ts, 349, 94)) ->P : Symbol(P, Decl(jsxElementType.tsx, 15, 35)) +>P : Symbol(P, Decl(jsxElementType.tsx, 16, 35)) declare global { ->global : Symbol(global, Decl(jsxElementType.tsx, 17, 48)) +>global : Symbol(global, Decl(jsxElementType.tsx, 18, 48)) namespace JSX { ->JSX : Symbol(JSX, Decl(react16.d.ts, 2493, 12), Decl(jsxElementType.tsx, 19, 16)) +>JSX : Symbol(JSX, Decl(react16.d.ts, 2493, 12), Decl(jsxElementType.tsx, 20, 16)) type ElementType = string | NewReactJSXElementConstructor; ->ElementType : Symbol(ElementType, Decl(jsxElementType.tsx, 20, 17)) ->NewReactJSXElementConstructor : Symbol(NewReactJSXElementConstructor, Decl(jsxElementType.tsx, 12, 14)) +>ElementType : Symbol(ElementType, Decl(jsxElementType.tsx, 21, 17)) +>NewReactJSXElementConstructor : Symbol(NewReactJSXElementConstructor, Decl(jsxElementType.tsx, 13, 30)) interface IntrinsicElements { ->IntrinsicElements : Symbol(IntrinsicElements, Decl(react16.d.ts, 2514, 86), Decl(jsxElementType.tsx, 21, 67)) +>IntrinsicElements : Symbol(IntrinsicElements, Decl(react16.d.ts, 2514, 86), Decl(jsxElementType.tsx, 22, 67)) ['my-web-component']: React.DOMAttributes; ->['my-web-component'] : Symbol(IntrinsicElements['my-web-component'], Decl(jsxElementType.tsx, 22, 33)) ->'my-web-component' : Symbol(IntrinsicElements['my-web-component'], Decl(jsxElementType.tsx, 22, 33)) +>['my-web-component'] : Symbol(IntrinsicElements['my-web-component'], Decl(jsxElementType.tsx, 23, 33)) +>'my-web-component' : Symbol(IntrinsicElements['my-web-component'], Decl(jsxElementType.tsx, 23, 33)) >React : Symbol(React, Decl(jsxElementType.tsx, 1, 6)) >DOMAttributes : Symbol(React.DOMAttributes, Decl(react16.d.ts, 844, 9)) } @@ -68,84 +71,83 @@ declare global { } let Component: NewReactJSXElementConstructor<{ title: string }>; ->Component : Symbol(Component, Decl(jsxElementType.tsx, 28, 3)) ->NewReactJSXElementConstructor : Symbol(NewReactJSXElementConstructor, Decl(jsxElementType.tsx, 12, 14)) ->title : Symbol(title, Decl(jsxElementType.tsx, 28, 46)) +>Component : Symbol(Component, Decl(jsxElementType.tsx, 29, 3)) +>NewReactJSXElementConstructor : Symbol(NewReactJSXElementConstructor, Decl(jsxElementType.tsx, 13, 30)) +>title : Symbol(title, Decl(jsxElementType.tsx, 29, 46)) const RenderString = ({ title }: { title: string }) => title; ->RenderString : Symbol(RenderString, Decl(jsxElementType.tsx, 30, 5)) ->title : Symbol(title, Decl(jsxElementType.tsx, 30, 23)) ->title : Symbol(title, Decl(jsxElementType.tsx, 30, 34)) ->title : Symbol(title, Decl(jsxElementType.tsx, 30, 23)) +>RenderString : Symbol(RenderString, Decl(jsxElementType.tsx, 31, 5)) +>title : Symbol(title, Decl(jsxElementType.tsx, 31, 23)) +>title : Symbol(title, Decl(jsxElementType.tsx, 31, 34)) +>title : Symbol(title, Decl(jsxElementType.tsx, 31, 23)) Component = RenderString; ->Component : Symbol(Component, Decl(jsxElementType.tsx, 28, 3)) ->RenderString : Symbol(RenderString, Decl(jsxElementType.tsx, 30, 5)) +>Component : Symbol(Component, Decl(jsxElementType.tsx, 29, 3)) +>RenderString : Symbol(RenderString, Decl(jsxElementType.tsx, 31, 5)) ; ->RenderString : Symbol(RenderString, Decl(jsxElementType.tsx, 30, 5)) +>RenderString : Symbol(RenderString, Decl(jsxElementType.tsx, 31, 5)) ; ->RenderString : Symbol(RenderString, Decl(jsxElementType.tsx, 30, 5)) ->title : Symbol(title, Decl(jsxElementType.tsx, 33, 13)) +>RenderString : Symbol(RenderString, Decl(jsxElementType.tsx, 31, 5)) +>title : Symbol(title, Decl(jsxElementType.tsx, 34, 13)) ; ->RenderString : Symbol(RenderString, Decl(jsxElementType.tsx, 30, 5)) ->excessProp : Symbol(excessProp, Decl(jsxElementType.tsx, 34, 13)) +>RenderString : Symbol(RenderString, Decl(jsxElementType.tsx, 31, 5)) +>excessProp : Symbol(excessProp, Decl(jsxElementType.tsx, 35, 13)) const RenderNumber = ({ title }: { title: string }) => title.length; ->RenderNumber : Symbol(RenderNumber, Decl(jsxElementType.tsx, 36, 5)) ->title : Symbol(title, Decl(jsxElementType.tsx, 36, 23)) ->title : Symbol(title, Decl(jsxElementType.tsx, 36, 34)) +>RenderNumber : Symbol(RenderNumber, Decl(jsxElementType.tsx, 37, 5)) +>title : Symbol(title, Decl(jsxElementType.tsx, 37, 23)) +>title : Symbol(title, Decl(jsxElementType.tsx, 37, 34)) >title.length : Symbol(String.length, Decl(lib.es5.d.ts, --, --)) ->title : Symbol(title, Decl(jsxElementType.tsx, 36, 23)) +>title : Symbol(title, Decl(jsxElementType.tsx, 37, 23)) >length : Symbol(String.length, Decl(lib.es5.d.ts, --, --)) Component = RenderNumber; ->Component : Symbol(Component, Decl(jsxElementType.tsx, 28, 3)) ->RenderNumber : Symbol(RenderNumber, Decl(jsxElementType.tsx, 36, 5)) +>Component : Symbol(Component, Decl(jsxElementType.tsx, 29, 3)) +>RenderNumber : Symbol(RenderNumber, Decl(jsxElementType.tsx, 37, 5)) ; ->RenderNumber : Symbol(RenderNumber, Decl(jsxElementType.tsx, 36, 5)) +>RenderNumber : Symbol(RenderNumber, Decl(jsxElementType.tsx, 37, 5)) ; ->RenderNumber : Symbol(RenderNumber, Decl(jsxElementType.tsx, 36, 5)) ->title : Symbol(title, Decl(jsxElementType.tsx, 39, 13)) +>RenderNumber : Symbol(RenderNumber, Decl(jsxElementType.tsx, 37, 5)) +>title : Symbol(title, Decl(jsxElementType.tsx, 40, 13)) ; ->RenderNumber : Symbol(RenderNumber, Decl(jsxElementType.tsx, 36, 5)) ->excessProp : Symbol(excessProp, Decl(jsxElementType.tsx, 40, 13)) +>RenderNumber : Symbol(RenderNumber, Decl(jsxElementType.tsx, 37, 5)) +>excessProp : Symbol(excessProp, Decl(jsxElementType.tsx, 41, 13)) const RenderArray = ({ title }: { title: string }) => [title]; ->RenderArray : Symbol(RenderArray, Decl(jsxElementType.tsx, 42, 5)) ->title : Symbol(title, Decl(jsxElementType.tsx, 42, 22)) ->title : Symbol(title, Decl(jsxElementType.tsx, 42, 33)) ->title : Symbol(title, Decl(jsxElementType.tsx, 42, 22)) +>RenderArray : Symbol(RenderArray, Decl(jsxElementType.tsx, 43, 5)) +>title : Symbol(title, Decl(jsxElementType.tsx, 43, 22)) +>title : Symbol(title, Decl(jsxElementType.tsx, 43, 33)) +>title : Symbol(title, Decl(jsxElementType.tsx, 43, 22)) Component = RenderArray; ->Component : Symbol(Component, Decl(jsxElementType.tsx, 28, 3)) ->RenderArray : Symbol(RenderArray, Decl(jsxElementType.tsx, 42, 5)) +>Component : Symbol(Component, Decl(jsxElementType.tsx, 29, 3)) +>RenderArray : Symbol(RenderArray, Decl(jsxElementType.tsx, 43, 5)) ; ->RenderArray : Symbol(RenderArray, Decl(jsxElementType.tsx, 42, 5)) +>RenderArray : Symbol(RenderArray, Decl(jsxElementType.tsx, 43, 5)) ; ->RenderArray : Symbol(RenderArray, Decl(jsxElementType.tsx, 42, 5)) ->title : Symbol(title, Decl(jsxElementType.tsx, 45, 12)) +>RenderArray : Symbol(RenderArray, Decl(jsxElementType.tsx, 43, 5)) +>title : Symbol(title, Decl(jsxElementType.tsx, 46, 12)) ; ->RenderArray : Symbol(RenderArray, Decl(jsxElementType.tsx, 42, 5)) ->excessProp : Symbol(excessProp, Decl(jsxElementType.tsx, 46, 12)) +>RenderArray : Symbol(RenderArray, Decl(jsxElementType.tsx, 43, 5)) +>excessProp : Symbol(excessProp, Decl(jsxElementType.tsx, 47, 12)) -// Future ReactNode can be Promises. -// But they should be rejected in React 18.0. +// React Server Component const RenderPromise = async ({ title }: { title: string }) => "react"; >RenderPromise : Symbol(RenderPromise, Decl(jsxElementType.tsx, 50, 5)) >title : Symbol(title, Decl(jsxElementType.tsx, 50, 30)) >title : Symbol(title, Decl(jsxElementType.tsx, 50, 41)) Component = RenderPromise; ->Component : Symbol(Component, Decl(jsxElementType.tsx, 28, 3)) +>Component : Symbol(Component, Decl(jsxElementType.tsx, 29, 3)) >RenderPromise : Symbol(RenderPromise, Decl(jsxElementType.tsx, 50, 5)) ; @@ -164,7 +166,7 @@ Component = RenderPromise; >div : Symbol(JSX.IntrinsicElements.div, Decl(react16.d.ts, 2546, 114)) ; ->my-web-component : Symbol(JSX.IntrinsicElements['my-web-component'], Decl(jsxElementType.tsx, 22, 33)) +>my-web-component : Symbol(JSX.IntrinsicElements['my-web-component'], Decl(jsxElementType.tsx, 23, 33)) // Highlighting various ecosystem compat issues // react-native-gesture-handler diff --git a/tests/baselines/reference/jsxElementType.types b/tests/baselines/reference/jsxElementType.types index 5f97eb8ab3da3..093cc01919dda 100644 --- a/tests/baselines/reference/jsxElementType.types +++ b/tests/baselines/reference/jsxElementType.types @@ -7,7 +7,7 @@ type React18ReactFragment = ReadonlyArray; >React18ReactFragment : readonly React18ReactNode[] type React18ReactNode = ->React18ReactNode : string | number | boolean | React.ReactElement | React.ReactPortal | React18ReactFragment | null | undefined +>React18ReactNode : string | number | boolean | React.ReactElement | React.ReactPortal | React18ReactFragment | Promise | null | undefined | React.ReactElement >React : any @@ -22,7 +22,8 @@ type React18ReactNode = | null >null : null - | undefined; + | undefined + | Promise; // // React.JSXElementConstructor but it now can return React nodes from function components. type NewReactJSXElementConstructor

= @@ -136,8 +137,7 @@ Component = RenderArray; >RenderArray : ({ title }: { title: string; }) => string[] >excessProp : true -// Future ReactNode can be Promises. -// But they should be rejected in React 18.0. +// React Server Component const RenderPromise = async ({ title }: { title: string }) => "react"; >RenderPromise : ({ title }: { title: string; }) => Promise >async ({ title }: { title: string }) => "react" : ({ title }: { title: string; }) => Promise diff --git a/tests/cases/compiler/jsxElementType.tsx b/tests/cases/compiler/jsxElementType.tsx index 7943133e54acb..35175b35bfbfc 100644 --- a/tests/cases/compiler/jsxElementType.tsx +++ b/tests/cases/compiler/jsxElementType.tsx @@ -12,7 +12,8 @@ type React18ReactNode = | React.ReactPortal | boolean | null - | undefined; + | undefined + | Promise; // // React.JSXElementConstructor but it now can return React nodes from function components. type NewReactJSXElementConstructor

= @@ -48,8 +49,7 @@ Component = RenderArray; ; ; -// Future ReactNode can be Promises. -// But they should be rejected in React 18.0. +// React Server Component const RenderPromise = async ({ title }: { title: string }) => "react"; Component = RenderPromise; ; From 4a046338cc6f09fb60bcb70d9e46109d3ecdeded Mon Sep 17 00:00:00 2001 From: eps1lon Date: Sun, 2 Apr 2023 10:01:30 +0200 Subject: [PATCH 09/19] Refine error message --- src/compiler/checker.ts | 3 +-- src/compiler/diagnosticMessages.json | 4 ++++ tests/baselines/reference/jsxElementType.errors.txt | 4 ++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 60b9b37f01786..696e79a1c79e1 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -30526,8 +30526,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { ? // TODO: Should this be a literal that library authors could potentially check against? stringType : getApparentType(checkExpression(jsxOpeningLikeNode.tagName)); - // TODO: error message - checkTypeRelatedTo(tagType, elementTypeConstraint, assignableRelation, jsxOpeningLikeNode.tagName, Diagnostics.Its_instance_type_0_is_not_a_valid_JSX_element, () => { + checkTypeRelatedTo(tagType, elementTypeConstraint, assignableRelation, jsxOpeningLikeNode.tagName, Diagnostics.Its_type_0_is_not_a_valid_JSX_element_type, () => { const componentName = getTextOfNode(jsxOpeningLikeNode.tagName); return chainDiagnosticMessages(/* details */ undefined, Diagnostics._0_cannot_be_used_as_a_JSX_component, componentName); }); diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index b8ffc66a08443..e9f283e6721c3 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -7720,5 +7720,9 @@ "Compiler option '{0}' cannot be given an empty string.": { "category": "Error", "code": 18051 + }, + "Its type '{0}' is not a valid JSX element type.": { + "category": "Error", + "code": 18052 } } diff --git a/tests/baselines/reference/jsxElementType.errors.txt b/tests/baselines/reference/jsxElementType.errors.txt index 4f7e69c9bccb7..9dfb23671ed7e 100644 --- a/tests/baselines/reference/jsxElementType.errors.txt +++ b/tests/baselines/reference/jsxElementType.errors.txt @@ -11,7 +11,7 @@ tests/cases/compiler/jsxElementType.tsx(53,2): error TS2741: Property 'title' is tests/cases/compiler/jsxElementType.tsx(55,16): error TS2322: Type '{ excessProp: true; }' is not assignable to type 'IntrinsicAttributes & { title: string; }'. Property 'excessProp' does not exist on type 'IntrinsicAttributes & { title: string; }'. tests/cases/compiler/jsxElementType.tsx(71,2): error TS2786: 'ReactNativeFlatList' cannot be used as a JSX component. - Its instance type '(props: {}, ref: ForwardedRef) => null' is not a valid JSX element. + Its type '(props: {}, ref: ForwardedRef) => null' is not a valid JSX element type. Type '(props: {}, ref: ForwardedRef) => null' is not assignable to type '(props: any) => React18ReactNode'. @@ -113,5 +113,5 @@ tests/cases/compiler/jsxElementType.tsx(71,2): error TS2786: 'ReactNativeFlatLis ; ~~~~~~~~~~~~~~~~~~~ !!! error TS2786: 'ReactNativeFlatList' cannot be used as a JSX component. -!!! error TS2786: Its instance type '(props: {}, ref: ForwardedRef) => null' is not a valid JSX element. +!!! error TS2786: Its type '(props: {}, ref: ForwardedRef) => null' is not a valid JSX element type. !!! error TS2786: Type '(props: {}, ref: ForwardedRef) => null' is not assignable to type '(props: any) => React18ReactNode'. \ No newline at end of file From a4c822056cbbeaa52e0e2305d001aa3581b27914 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Tue, 11 Apr 2023 13:10:58 -0700 Subject: [PATCH 10/19] Fix up comment for linter. --- src/compiler/checker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index af6c757cb275c..f278dea9ecf96 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -30870,7 +30870,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { : getApparentType(checkExpression(jsxOpeningLikeNode.tagName)); checkTypeRelatedTo(tagType, elementTypeConstraint, assignableRelation, jsxOpeningLikeNode.tagName, Diagnostics.Its_type_0_is_not_a_valid_JSX_element_type, () => { const componentName = getTextOfNode(jsxOpeningLikeNode.tagName); - return chainDiagnosticMessages(/* details */ undefined, Diagnostics._0_cannot_be_used_as_a_JSX_component, componentName); + return chainDiagnosticMessages(/*details*/ undefined, Diagnostics._0_cannot_be_used_as_a_JSX_component, componentName); }); } else { From 315e0b2cb7e3a7fa04ed6ff96de2871af7cbaaf0 Mon Sep 17 00:00:00 2001 From: eps1lon Date: Thu, 13 Apr 2023 04:30:53 +0200 Subject: [PATCH 11/19] Sanity checks for render elements and class components --- .../reference/jsxElementType.errors.txt | 74 +++++++-- tests/baselines/reference/jsxElementType.js | 55 +++++++ .../reference/jsxElementType.symbols | 149 ++++++++++++------ .../baselines/reference/jsxElementType.types | 67 ++++++++ tests/cases/compiler/jsxElementType.tsx | 17 ++ 5 files changed, 306 insertions(+), 56 deletions(-) diff --git a/tests/baselines/reference/jsxElementType.errors.txt b/tests/baselines/reference/jsxElementType.errors.txt index 2658b8eec2a70..8bb9e660d8aba 100644 --- a/tests/baselines/reference/jsxElementType.errors.txt +++ b/tests/baselines/reference/jsxElementType.errors.txt @@ -1,22 +1,37 @@ tests/cases/compiler/jsxElementType.tsx(34,2): error TS2741: Property 'title' is missing in type '{}' but required in type '{ title: string; }'. -tests/cases/compiler/jsxElementType.tsx(36,15): error TS2322: Type '{ excessProp: true; }' is not assignable to type 'IntrinsicAttributes & { title: string; }'. +tests/cases/compiler/jsxElementType.tsx(36,16): error TS2322: Type '{ excessProp: true; }' is not assignable to type 'IntrinsicAttributes & { title: string; }'. Property 'excessProp' does not exist on type 'IntrinsicAttributes & { title: string; }'. tests/cases/compiler/jsxElementType.tsx(40,2): error TS2741: Property 'title' is missing in type '{}' but required in type '{ title: string; }'. tests/cases/compiler/jsxElementType.tsx(42,15): error TS2322: Type '{ excessProp: true; }' is not assignable to type 'IntrinsicAttributes & { title: string; }'. Property 'excessProp' does not exist on type 'IntrinsicAttributes & { title: string; }'. tests/cases/compiler/jsxElementType.tsx(46,2): error TS2741: Property 'title' is missing in type '{}' but required in type '{ title: string; }'. -tests/cases/compiler/jsxElementType.tsx(48,14): error TS2322: Type '{ excessProp: true; }' is not assignable to type 'IntrinsicAttributes & { title: string; }'. +tests/cases/compiler/jsxElementType.tsx(48,15): error TS2322: Type '{ excessProp: true; }' is not assignable to type 'IntrinsicAttributes & { title: string; }'. Property 'excessProp' does not exist on type 'IntrinsicAttributes & { title: string; }'. -tests/cases/compiler/jsxElementType.tsx(53,2): error TS2741: Property 'title' is missing in type '{}' but required in type '{ title: string; }'. -tests/cases/compiler/jsxElementType.tsx(55,16): error TS2322: Type '{ excessProp: true; }' is not assignable to type 'IntrinsicAttributes & { title: string; }'. +tests/cases/compiler/jsxElementType.tsx(52,2): error TS2741: Property 'title' is missing in type '{}' but required in type '{ title: string; }'. +tests/cases/compiler/jsxElementType.tsx(54,14): error TS2322: Type '{ excessProp: true; }' is not assignable to type 'IntrinsicAttributes & { title: string; }'. Property 'excessProp' does not exist on type 'IntrinsicAttributes & { title: string; }'. -tests/cases/compiler/jsxElementType.tsx(71,2): error TS2786: 'ReactNativeFlatList' cannot be used as a JSX component. +tests/cases/compiler/jsxElementType.tsx(59,2): error TS2741: Property 'title' is missing in type '{}' but required in type '{ title: string; }'. +tests/cases/compiler/jsxElementType.tsx(61,16): error TS2322: Type '{ excessProp: true; }' is not assignable to type 'IntrinsicAttributes & { title: string; }'. + Property 'excessProp' does not exist on type 'IntrinsicAttributes & { title: string; }'. +tests/cases/compiler/jsxElementType.tsx(70,2): error TS2769: No overload matches this call. + Overload 1 of 2, '(props: Readonly<{ title: string; }>): RenderStringClass', gave the following error. + Property 'title' is missing in type '{}' but required in type 'Readonly<{ title: string; }>'. + Overload 2 of 2, '(props: { title: string; }, context?: any): RenderStringClass', gave the following error. + Property 'title' is missing in type '{}' but required in type 'Readonly<{ title: string; }>'. +tests/cases/compiler/jsxElementType.tsx(72,20): error TS2769: No overload matches this call. + Overload 1 of 2, '(props: Readonly<{ title: string; }>): RenderStringClass', gave the following error. + Type '{ excessProp: true; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes & Readonly<{ children?: ReactNode; }> & Readonly<{ title: string; }>'. + Property 'excessProp' does not exist on type 'IntrinsicAttributes & IntrinsicClassAttributes & Readonly<{ children?: ReactNode; }> & Readonly<{ title: string; }>'. + Overload 2 of 2, '(props: { title: string; }, context?: any): RenderStringClass', gave the following error. + Type '{ excessProp: true; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes & Readonly<{ children?: ReactNode; }> & Readonly<{ title: string; }>'. + Property 'excessProp' does not exist on type 'IntrinsicAttributes & IntrinsicClassAttributes & Readonly<{ children?: ReactNode; }> & Readonly<{ title: string; }>'. +tests/cases/compiler/jsxElementType.tsx(88,2): error TS2786: 'ReactNativeFlatList' cannot be used as a JSX component. Its type '(props: {}, ref: ForwardedRef) => null' is not a valid JSX element type. Type '(props: {}, ref: ForwardedRef) => null' is not assignable to type '(props: any) => React18ReactNode'. Target signature provides too few arguments. Expected 2 or more, but got 1. -==== tests/cases/compiler/jsxElementType.tsx (9 errors) ==== +==== tests/cases/compiler/jsxElementType.tsx (13 errors) ==== /// import * as React from "react"; @@ -48,12 +63,24 @@ tests/cases/compiler/jsxElementType.tsx(71,2): error TS2786: 'ReactNativeFlatLis let Component: NewReactJSXElementConstructor<{ title: string }>; + const RenderElement = ({ title }: { title: string }) =>

{title}
; + Component = RenderElement; + ; + ~~~~~~~~~~~~~ +!!! error TS2741: Property 'title' is missing in type '{}' but required in type '{ title: string; }'. +!!! related TS2728 tests/cases/compiler/jsxElementType.tsx:32:37: 'title' is declared here. + ; + ; + ~~~~~~~~~~ +!!! error TS2322: Type '{ excessProp: true; }' is not assignable to type 'IntrinsicAttributes & { title: string; }'. +!!! error TS2322: Property 'excessProp' does not exist on type 'IntrinsicAttributes & { title: string; }'. + const RenderString = ({ title }: { title: string }) => title; Component = RenderString; ; ~~~~~~~~~~~~ !!! error TS2741: Property 'title' is missing in type '{}' but required in type '{ title: string; }'. -!!! related TS2728 tests/cases/compiler/jsxElementType.tsx:32:36: 'title' is declared here. +!!! related TS2728 tests/cases/compiler/jsxElementType.tsx:38:36: 'title' is declared here. ; ; ~~~~~~~~~~ @@ -65,7 +92,7 @@ tests/cases/compiler/jsxElementType.tsx(71,2): error TS2786: 'ReactNativeFlatLis ; ~~~~~~~~~~~~ !!! error TS2741: Property 'title' is missing in type '{}' but required in type '{ title: string; }'. -!!! related TS2728 tests/cases/compiler/jsxElementType.tsx:38:36: 'title' is declared here. +!!! related TS2728 tests/cases/compiler/jsxElementType.tsx:44:36: 'title' is declared here. ; ; ~~~~~~~~~~ @@ -77,7 +104,7 @@ tests/cases/compiler/jsxElementType.tsx(71,2): error TS2786: 'ReactNativeFlatLis ; ~~~~~~~~~~~ !!! error TS2741: Property 'title' is missing in type '{}' but required in type '{ title: string; }'. -!!! related TS2728 tests/cases/compiler/jsxElementType.tsx:44:35: 'title' is declared here. +!!! related TS2728 tests/cases/compiler/jsxElementType.tsx:50:35: 'title' is declared here. ; ; ~~~~~~~~~~ @@ -90,13 +117,40 @@ tests/cases/compiler/jsxElementType.tsx(71,2): error TS2786: 'ReactNativeFlatLis ; ~~~~~~~~~~~~~ !!! error TS2741: Property 'title' is missing in type '{}' but required in type '{ title: string; }'. -!!! related TS2728 tests/cases/compiler/jsxElementType.tsx:51:43: 'title' is declared here. +!!! related TS2728 tests/cases/compiler/jsxElementType.tsx:57:43: 'title' is declared here. ; ; ~~~~~~~~~~ !!! error TS2322: Type '{ excessProp: true; }' is not assignable to type 'IntrinsicAttributes & { title: string; }'. !!! error TS2322: Property 'excessProp' does not exist on type 'IntrinsicAttributes & { title: string; }'. + // Class components still work + class RenderStringClass extends React.Component<{ title: string }> { + render() { + return this.props.title; + } + } + Component = RenderStringClass; + ; + ~~~~~~~~~~~~~~~~~ +!!! error TS2769: No overload matches this call. +!!! error TS2769: Overload 1 of 2, '(props: Readonly<{ title: string; }>): RenderStringClass', gave the following error. +!!! error TS2769: Property 'title' is missing in type '{}' but required in type 'Readonly<{ title: string; }>'. +!!! error TS2769: Overload 2 of 2, '(props: { title: string; }, context?: any): RenderStringClass', gave the following error. +!!! error TS2769: Property 'title' is missing in type '{}' but required in type 'Readonly<{ title: string; }>'. +!!! related TS2728 tests/cases/compiler/jsxElementType.tsx:64:51: 'title' is declared here. +!!! related TS2728 tests/cases/compiler/jsxElementType.tsx:64:51: 'title' is declared here. + ; + ; + ~~~~~~~~~~ +!!! error TS2769: No overload matches this call. +!!! error TS2769: Overload 1 of 2, '(props: Readonly<{ title: string; }>): RenderStringClass', gave the following error. +!!! error TS2769: Type '{ excessProp: true; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes & Readonly<{ children?: ReactNode; }> & Readonly<{ title: string; }>'. +!!! error TS2769: Property 'excessProp' does not exist on type 'IntrinsicAttributes & IntrinsicClassAttributes & Readonly<{ children?: ReactNode; }> & Readonly<{ title: string; }>'. +!!! error TS2769: Overload 2 of 2, '(props: { title: string; }, context?: any): RenderStringClass', gave the following error. +!!! error TS2769: Type '{ excessProp: true; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes & Readonly<{ children?: ReactNode; }> & Readonly<{ title: string; }>'. +!!! error TS2769: Property 'excessProp' does not exist on type 'IntrinsicAttributes & IntrinsicClassAttributes & Readonly<{ children?: ReactNode; }> & Readonly<{ title: string; }>'. + // Host element types still work
; ; diff --git a/tests/baselines/reference/jsxElementType.js b/tests/baselines/reference/jsxElementType.js index 24f018d2b6377..c32527a41dec6 100644 --- a/tests/baselines/reference/jsxElementType.js +++ b/tests/baselines/reference/jsxElementType.js @@ -30,6 +30,12 @@ declare global { let Component: NewReactJSXElementConstructor<{ title: string }>; +const RenderElement = ({ title }: { title: string }) =>
{title}
; +Component = RenderElement; +; +; +; + const RenderString = ({ title }: { title: string }) => title; Component = RenderString; ; @@ -55,6 +61,17 @@ Component = RenderPromise; ; ; +// Class components still work +class RenderStringClass extends React.Component<{ title: string }> { + render() { + return this.props.title; + } +} +Component = RenderStringClass; +; +; +; + // Host element types still work
; ; @@ -73,6 +90,21 @@ function ReactNativeFlatList( //// [jsxElementType.js] "use strict"; +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { @@ -113,6 +145,14 @@ Object.defineProperty(exports, "__esModule", { value: true }); /// var React = require("react"); var Component; +var RenderElement = function (_a) { + var title = _a.title; + return React.createElement("div", null, title); +}; +Component = RenderElement; +React.createElement(RenderElement, null); +React.createElement(RenderElement, { title: "react" }); +React.createElement(RenderElement, { excessProp: true }); var RenderString = function (_a) { var title = _a.title; return title; @@ -148,6 +188,21 @@ Component = RenderPromise; React.createElement(RenderPromise, null); React.createElement(RenderPromise, { title: "react" }); React.createElement(RenderPromise, { excessProp: true }); +// Class components still work +var RenderStringClass = /** @class */ (function (_super) { + __extends(RenderStringClass, _super); + function RenderStringClass() { + return _super !== null && _super.apply(this, arguments) || this; + } + RenderStringClass.prototype.render = function () { + return this.props.title; + }; + return RenderStringClass; +}(React.Component)); +Component = RenderStringClass; +React.createElement(RenderStringClass, null); +React.createElement(RenderStringClass, { title: "react" }); +React.createElement(RenderStringClass, { excessProp: true }); // Host element types still work React.createElement("div", null); React.createElement("my-web-component", null); diff --git a/tests/baselines/reference/jsxElementType.symbols b/tests/baselines/reference/jsxElementType.symbols index 35a951a602c23..3d7896e741c71 100644 --- a/tests/baselines/reference/jsxElementType.symbols +++ b/tests/baselines/reference/jsxElementType.symbols @@ -75,91 +75,148 @@ let Component: NewReactJSXElementConstructor<{ title: string }>; >NewReactJSXElementConstructor : Symbol(NewReactJSXElementConstructor, Decl(jsxElementType.tsx, 13, 30)) >title : Symbol(title, Decl(jsxElementType.tsx, 29, 46)) +const RenderElement = ({ title }: { title: string }) =>
{title}
; +>RenderElement : Symbol(RenderElement, Decl(jsxElementType.tsx, 31, 5)) +>title : Symbol(title, Decl(jsxElementType.tsx, 31, 24)) +>title : Symbol(title, Decl(jsxElementType.tsx, 31, 35)) +>div : Symbol(JSX.IntrinsicElements.div, Decl(react16.d.ts, 2546, 114)) +>title : Symbol(title, Decl(jsxElementType.tsx, 31, 24)) +>div : Symbol(JSX.IntrinsicElements.div, Decl(react16.d.ts, 2546, 114)) + +Component = RenderElement; +>Component : Symbol(Component, Decl(jsxElementType.tsx, 29, 3)) +>RenderElement : Symbol(RenderElement, Decl(jsxElementType.tsx, 31, 5)) + +; +>RenderElement : Symbol(RenderElement, Decl(jsxElementType.tsx, 31, 5)) + +; +>RenderElement : Symbol(RenderElement, Decl(jsxElementType.tsx, 31, 5)) +>title : Symbol(title, Decl(jsxElementType.tsx, 34, 14)) + +; +>RenderElement : Symbol(RenderElement, Decl(jsxElementType.tsx, 31, 5)) +>excessProp : Symbol(excessProp, Decl(jsxElementType.tsx, 35, 14)) + const RenderString = ({ title }: { title: string }) => title; ->RenderString : Symbol(RenderString, Decl(jsxElementType.tsx, 31, 5)) ->title : Symbol(title, Decl(jsxElementType.tsx, 31, 23)) ->title : Symbol(title, Decl(jsxElementType.tsx, 31, 34)) ->title : Symbol(title, Decl(jsxElementType.tsx, 31, 23)) +>RenderString : Symbol(RenderString, Decl(jsxElementType.tsx, 37, 5)) +>title : Symbol(title, Decl(jsxElementType.tsx, 37, 23)) +>title : Symbol(title, Decl(jsxElementType.tsx, 37, 34)) +>title : Symbol(title, Decl(jsxElementType.tsx, 37, 23)) Component = RenderString; >Component : Symbol(Component, Decl(jsxElementType.tsx, 29, 3)) ->RenderString : Symbol(RenderString, Decl(jsxElementType.tsx, 31, 5)) +>RenderString : Symbol(RenderString, Decl(jsxElementType.tsx, 37, 5)) ; ->RenderString : Symbol(RenderString, Decl(jsxElementType.tsx, 31, 5)) +>RenderString : Symbol(RenderString, Decl(jsxElementType.tsx, 37, 5)) ; ->RenderString : Symbol(RenderString, Decl(jsxElementType.tsx, 31, 5)) ->title : Symbol(title, Decl(jsxElementType.tsx, 34, 13)) +>RenderString : Symbol(RenderString, Decl(jsxElementType.tsx, 37, 5)) +>title : Symbol(title, Decl(jsxElementType.tsx, 40, 13)) ; ->RenderString : Symbol(RenderString, Decl(jsxElementType.tsx, 31, 5)) ->excessProp : Symbol(excessProp, Decl(jsxElementType.tsx, 35, 13)) +>RenderString : Symbol(RenderString, Decl(jsxElementType.tsx, 37, 5)) +>excessProp : Symbol(excessProp, Decl(jsxElementType.tsx, 41, 13)) const RenderNumber = ({ title }: { title: string }) => title.length; ->RenderNumber : Symbol(RenderNumber, Decl(jsxElementType.tsx, 37, 5)) ->title : Symbol(title, Decl(jsxElementType.tsx, 37, 23)) ->title : Symbol(title, Decl(jsxElementType.tsx, 37, 34)) +>RenderNumber : Symbol(RenderNumber, Decl(jsxElementType.tsx, 43, 5)) +>title : Symbol(title, Decl(jsxElementType.tsx, 43, 23)) +>title : Symbol(title, Decl(jsxElementType.tsx, 43, 34)) >title.length : Symbol(String.length, Decl(lib.es5.d.ts, --, --)) ->title : Symbol(title, Decl(jsxElementType.tsx, 37, 23)) +>title : Symbol(title, Decl(jsxElementType.tsx, 43, 23)) >length : Symbol(String.length, Decl(lib.es5.d.ts, --, --)) Component = RenderNumber; >Component : Symbol(Component, Decl(jsxElementType.tsx, 29, 3)) ->RenderNumber : Symbol(RenderNumber, Decl(jsxElementType.tsx, 37, 5)) +>RenderNumber : Symbol(RenderNumber, Decl(jsxElementType.tsx, 43, 5)) ; ->RenderNumber : Symbol(RenderNumber, Decl(jsxElementType.tsx, 37, 5)) +>RenderNumber : Symbol(RenderNumber, Decl(jsxElementType.tsx, 43, 5)) ; ->RenderNumber : Symbol(RenderNumber, Decl(jsxElementType.tsx, 37, 5)) ->title : Symbol(title, Decl(jsxElementType.tsx, 40, 13)) +>RenderNumber : Symbol(RenderNumber, Decl(jsxElementType.tsx, 43, 5)) +>title : Symbol(title, Decl(jsxElementType.tsx, 46, 13)) ; ->RenderNumber : Symbol(RenderNumber, Decl(jsxElementType.tsx, 37, 5)) ->excessProp : Symbol(excessProp, Decl(jsxElementType.tsx, 41, 13)) +>RenderNumber : Symbol(RenderNumber, Decl(jsxElementType.tsx, 43, 5)) +>excessProp : Symbol(excessProp, Decl(jsxElementType.tsx, 47, 13)) const RenderArray = ({ title }: { title: string }) => [title]; ->RenderArray : Symbol(RenderArray, Decl(jsxElementType.tsx, 43, 5)) ->title : Symbol(title, Decl(jsxElementType.tsx, 43, 22)) ->title : Symbol(title, Decl(jsxElementType.tsx, 43, 33)) ->title : Symbol(title, Decl(jsxElementType.tsx, 43, 22)) +>RenderArray : Symbol(RenderArray, Decl(jsxElementType.tsx, 49, 5)) +>title : Symbol(title, Decl(jsxElementType.tsx, 49, 22)) +>title : Symbol(title, Decl(jsxElementType.tsx, 49, 33)) +>title : Symbol(title, Decl(jsxElementType.tsx, 49, 22)) Component = RenderArray; >Component : Symbol(Component, Decl(jsxElementType.tsx, 29, 3)) ->RenderArray : Symbol(RenderArray, Decl(jsxElementType.tsx, 43, 5)) +>RenderArray : Symbol(RenderArray, Decl(jsxElementType.tsx, 49, 5)) ; ->RenderArray : Symbol(RenderArray, Decl(jsxElementType.tsx, 43, 5)) +>RenderArray : Symbol(RenderArray, Decl(jsxElementType.tsx, 49, 5)) ; ->RenderArray : Symbol(RenderArray, Decl(jsxElementType.tsx, 43, 5)) ->title : Symbol(title, Decl(jsxElementType.tsx, 46, 12)) +>RenderArray : Symbol(RenderArray, Decl(jsxElementType.tsx, 49, 5)) +>title : Symbol(title, Decl(jsxElementType.tsx, 52, 12)) ; ->RenderArray : Symbol(RenderArray, Decl(jsxElementType.tsx, 43, 5)) ->excessProp : Symbol(excessProp, Decl(jsxElementType.tsx, 47, 12)) +>RenderArray : Symbol(RenderArray, Decl(jsxElementType.tsx, 49, 5)) +>excessProp : Symbol(excessProp, Decl(jsxElementType.tsx, 53, 12)) // React Server Component const RenderPromise = async ({ title }: { title: string }) => "react"; ->RenderPromise : Symbol(RenderPromise, Decl(jsxElementType.tsx, 50, 5)) ->title : Symbol(title, Decl(jsxElementType.tsx, 50, 30)) ->title : Symbol(title, Decl(jsxElementType.tsx, 50, 41)) +>RenderPromise : Symbol(RenderPromise, Decl(jsxElementType.tsx, 56, 5)) +>title : Symbol(title, Decl(jsxElementType.tsx, 56, 30)) +>title : Symbol(title, Decl(jsxElementType.tsx, 56, 41)) Component = RenderPromise; >Component : Symbol(Component, Decl(jsxElementType.tsx, 29, 3)) ->RenderPromise : Symbol(RenderPromise, Decl(jsxElementType.tsx, 50, 5)) +>RenderPromise : Symbol(RenderPromise, Decl(jsxElementType.tsx, 56, 5)) ; ->RenderPromise : Symbol(RenderPromise, Decl(jsxElementType.tsx, 50, 5)) +>RenderPromise : Symbol(RenderPromise, Decl(jsxElementType.tsx, 56, 5)) ; ->RenderPromise : Symbol(RenderPromise, Decl(jsxElementType.tsx, 50, 5)) ->title : Symbol(title, Decl(jsxElementType.tsx, 53, 14)) +>RenderPromise : Symbol(RenderPromise, Decl(jsxElementType.tsx, 56, 5)) +>title : Symbol(title, Decl(jsxElementType.tsx, 59, 14)) ; ->RenderPromise : Symbol(RenderPromise, Decl(jsxElementType.tsx, 50, 5)) ->excessProp : Symbol(excessProp, Decl(jsxElementType.tsx, 54, 14)) +>RenderPromise : Symbol(RenderPromise, Decl(jsxElementType.tsx, 56, 5)) +>excessProp : Symbol(excessProp, Decl(jsxElementType.tsx, 60, 14)) + +// Class components still work +class RenderStringClass extends React.Component<{ title: string }> { +>RenderStringClass : Symbol(RenderStringClass, Decl(jsxElementType.tsx, 60, 29)) +>React.Component : Symbol(React.Component, Decl(react16.d.ts, 345, 54), Decl(react16.d.ts, 349, 94)) +>React : Symbol(React, Decl(jsxElementType.tsx, 1, 6)) +>Component : Symbol(React.Component, Decl(react16.d.ts, 345, 54), Decl(react16.d.ts, 349, 94)) +>title : Symbol(title, Decl(jsxElementType.tsx, 63, 49)) + + render() { +>render : Symbol(RenderStringClass.render, Decl(jsxElementType.tsx, 63, 68)) + + return this.props.title; +>this.props.title : Symbol(title, Decl(jsxElementType.tsx, 63, 49)) +>this.props : Symbol(React.Component.props, Decl(react16.d.ts, 367, 32)) +>this : Symbol(RenderStringClass, Decl(jsxElementType.tsx, 60, 29)) +>props : Symbol(React.Component.props, Decl(react16.d.ts, 367, 32)) +>title : Symbol(title, Decl(jsxElementType.tsx, 63, 49)) + } +} +Component = RenderStringClass; +>Component : Symbol(Component, Decl(jsxElementType.tsx, 29, 3)) +>RenderStringClass : Symbol(RenderStringClass, Decl(jsxElementType.tsx, 60, 29)) + +; +>RenderStringClass : Symbol(RenderStringClass, Decl(jsxElementType.tsx, 60, 29)) + +; +>RenderStringClass : Symbol(RenderStringClass, Decl(jsxElementType.tsx, 60, 29)) +>title : Symbol(title, Decl(jsxElementType.tsx, 70, 18)) + +; +>RenderStringClass : Symbol(RenderStringClass, Decl(jsxElementType.tsx, 60, 29)) +>excessProp : Symbol(excessProp, Decl(jsxElementType.tsx, 71, 18)) // Host element types still work
; @@ -172,24 +229,24 @@ Component = RenderPromise; // react-native-gesture-handler // https://github.com/software-mansion/react-native-gesture-handler/blob/79017e5e7cc2e82e6467851f870920ff836ee04f/src/components/GestureComponents.tsx#L139-L146 interface ReactNativeFlatListProps {} ->ReactNativeFlatListProps : Symbol(ReactNativeFlatListProps, Decl(jsxElementType.tsx, 58, 21)) ->Item : Symbol(Item, Decl(jsxElementType.tsx, 63, 35)) +>ReactNativeFlatListProps : Symbol(ReactNativeFlatListProps, Decl(jsxElementType.tsx, 75, 21)) +>Item : Symbol(Item, Decl(jsxElementType.tsx, 80, 35)) function ReactNativeFlatList( ->ReactNativeFlatList : Symbol(ReactNativeFlatList, Decl(jsxElementType.tsx, 63, 43)) +>ReactNativeFlatList : Symbol(ReactNativeFlatList, Decl(jsxElementType.tsx, 80, 43)) props: {}, ->props : Symbol(props, Decl(jsxElementType.tsx, 64, 29)) +>props : Symbol(props, Decl(jsxElementType.tsx, 81, 29)) ref: React.ForwardedRef ->ref : Symbol(ref, Decl(jsxElementType.tsx, 65, 12)) +>ref : Symbol(ref, Decl(jsxElementType.tsx, 82, 12)) >React : Symbol(React, Decl(jsxElementType.tsx, 1, 6)) >ForwardedRef : Symbol(React.ForwardedRef, Decl(react16.d.ts, 2355, 9)) ->ReactNativeFlatList : Symbol(ReactNativeFlatList, Decl(jsxElementType.tsx, 63, 43)) +>ReactNativeFlatList : Symbol(ReactNativeFlatList, Decl(jsxElementType.tsx, 80, 43)) ) { return null; } ; ->ReactNativeFlatList : Symbol(ReactNativeFlatList, Decl(jsxElementType.tsx, 63, 43)) +>ReactNativeFlatList : Symbol(ReactNativeFlatList, Decl(jsxElementType.tsx, 80, 43)) diff --git a/tests/baselines/reference/jsxElementType.types b/tests/baselines/reference/jsxElementType.types index 0630ebcf7c1d4..10b837eed65c3 100644 --- a/tests/baselines/reference/jsxElementType.types +++ b/tests/baselines/reference/jsxElementType.types @@ -54,6 +54,35 @@ let Component: NewReactJSXElementConstructor<{ title: string }>; >Component : NewReactJSXElementConstructor<{ title: string; }> >title : string +const RenderElement = ({ title }: { title: string }) =>
{title}
; +>RenderElement : ({ title }: { title: string; }) => JSX.Element +>({ title }: { title: string }) =>
{title}
: ({ title }: { title: string; }) => JSX.Element +>title : string +>title : string +>
{title}
: JSX.Element +>div : any +>title : string +>div : any + +Component = RenderElement; +>Component = RenderElement : ({ title }: { title: string; }) => JSX.Element +>Component : NewReactJSXElementConstructor<{ title: string; }> +>RenderElement : ({ title }: { title: string; }) => JSX.Element + +; +> : JSX.Element +>RenderElement : ({ title }: { title: string; }) => JSX.Element + +; +> : JSX.Element +>RenderElement : ({ title }: { title: string; }) => JSX.Element +>title : string + +; +> : JSX.Element +>RenderElement : ({ title }: { title: string; }) => JSX.Element +>excessProp : true + const RenderString = ({ title }: { title: string }) => title; >RenderString : ({ title }: { title: string; }) => string >({ title }: { title: string }) => title : ({ title }: { title: string; }) => string @@ -162,6 +191,44 @@ Component = RenderPromise; >RenderPromise : ({ title }: { title: string; }) => Promise >excessProp : true +// Class components still work +class RenderStringClass extends React.Component<{ title: string }> { +>RenderStringClass : RenderStringClass +>React.Component : React.Component<{ title: string; }, {}, any> +>React : typeof React +>Component : typeof React.Component +>title : string + + render() { +>render : () => string + + return this.props.title; +>this.props.title : string +>this.props : Readonly<{ children?: React.ReactNode; }> & Readonly<{ title: string; }> +>this : this +>props : Readonly<{ children?: React.ReactNode; }> & Readonly<{ title: string; }> +>title : string + } +} +Component = RenderStringClass; +>Component = RenderStringClass : typeof RenderStringClass +>Component : NewReactJSXElementConstructor<{ title: string; }> +>RenderStringClass : typeof RenderStringClass + +; +> : JSX.Element +>RenderStringClass : typeof RenderStringClass + +; +> : JSX.Element +>RenderStringClass : typeof RenderStringClass +>title : string + +; +> : JSX.Element +>RenderStringClass : typeof RenderStringClass +>excessProp : true + // Host element types still work
; >
: JSX.Element diff --git a/tests/cases/compiler/jsxElementType.tsx b/tests/cases/compiler/jsxElementType.tsx index 35175b35bfbfc..6d8b0f5952446 100644 --- a/tests/cases/compiler/jsxElementType.tsx +++ b/tests/cases/compiler/jsxElementType.tsx @@ -31,6 +31,12 @@ declare global { let Component: NewReactJSXElementConstructor<{ title: string }>; +const RenderElement = ({ title }: { title: string }) =>
{title}
; +Component = RenderElement; +; +; +; + const RenderString = ({ title }: { title: string }) => title; Component = RenderString; ; @@ -56,6 +62,17 @@ Component = RenderPromise; ; ; +// Class components still work +class RenderStringClass extends React.Component<{ title: string }> { + render() { + return this.props.title; + } +} +Component = RenderStringClass; +; +; +; + // Host element types still work
; ; From af48970c33108c362a3e6abb20531fd02f4623ef Mon Sep 17 00:00:00 2001 From: eps1lon Date: Thu, 13 Apr 2023 04:47:28 +0200 Subject: [PATCH 12/19] higher-order component compat --- .../baselines/reference/jsxElementType.errors.txt | 13 +++++++++++-- tests/baselines/reference/jsxElementType.js | 12 +++++++++++- tests/baselines/reference/jsxElementType.symbols | 14 ++++++++++++++ tests/baselines/reference/jsxElementType.types | 12 ++++++++++++ tests/cases/compiler/jsxElementType.tsx | 7 ++++++- 5 files changed, 54 insertions(+), 4 deletions(-) diff --git a/tests/baselines/reference/jsxElementType.errors.txt b/tests/baselines/reference/jsxElementType.errors.txt index 8bb9e660d8aba..f8d4c778ac8c3 100644 --- a/tests/baselines/reference/jsxElementType.errors.txt +++ b/tests/baselines/reference/jsxElementType.errors.txt @@ -29,9 +29,10 @@ tests/cases/compiler/jsxElementType.tsx(88,2): error TS2786: 'ReactNativeFlatLis Its type '(props: {}, ref: ForwardedRef) => null' is not a valid JSX element type. Type '(props: {}, ref: ForwardedRef) => null' is not assignable to type '(props: any) => React18ReactNode'. Target signature provides too few arguments. Expected 2 or more, but got 1. +tests/cases/compiler/jsxElementType.tsx(92,11): error TS2322: Type '{}' is not assignable to type 'LibraryManagedAttributes'. -==== tests/cases/compiler/jsxElementType.tsx (13 errors) ==== +==== tests/cases/compiler/jsxElementType.tsx (14 errors) ==== /// import * as React from "react"; @@ -170,4 +171,12 @@ tests/cases/compiler/jsxElementType.tsx(88,2): error TS2786: 'ReactNativeFlatLis !!! error TS2786: 'ReactNativeFlatList' cannot be used as a JSX component. !!! error TS2786: Its type '(props: {}, ref: ForwardedRef) => null' is not a valid JSX element type. !!! error TS2786: Type '(props: {}, ref: ForwardedRef) => null' is not assignable to type '(props: any) => React18ReactNode'. -!!! error TS2786: Target signature provides too few arguments. Expected 2 or more, but got 1. \ No newline at end of file +!!! error TS2786: Target signature provides too few arguments. Expected 2 or more, but got 1. + + // testing higher-order component compat + function f1 React.ReactElement>(Component: T) { + return ; + ~~~~~~~~~ +!!! error TS2322: Type '{}' is not assignable to type 'LibraryManagedAttributes'. + } + \ No newline at end of file diff --git a/tests/baselines/reference/jsxElementType.js b/tests/baselines/reference/jsxElementType.js index c32527a41dec6..abe0115d1c0e4 100644 --- a/tests/baselines/reference/jsxElementType.js +++ b/tests/baselines/reference/jsxElementType.js @@ -86,7 +86,13 @@ function ReactNativeFlatList( ) { return null; } -; +; + +// testing higher-order component compat +function f1 React.ReactElement>(Component: T) { + return ; +} + //// [jsxElementType.js] "use strict"; @@ -210,3 +216,7 @@ function ReactNativeFlatList(props, ref) { return null; } React.createElement(ReactNativeFlatList, null); +// testing higher-order component compat +function f1(Component) { + return React.createElement(Component, null); +} diff --git a/tests/baselines/reference/jsxElementType.symbols b/tests/baselines/reference/jsxElementType.symbols index 3d7896e741c71..b9ce3572dd243 100644 --- a/tests/baselines/reference/jsxElementType.symbols +++ b/tests/baselines/reference/jsxElementType.symbols @@ -250,3 +250,17 @@ function ReactNativeFlatList( ; >ReactNativeFlatList : Symbol(ReactNativeFlatList, Decl(jsxElementType.tsx, 80, 43)) +// testing higher-order component compat +function f1 React.ReactElement>(Component: T) { +>f1 : Symbol(f1, Decl(jsxElementType.tsx, 87, 24)) +>T : Symbol(T, Decl(jsxElementType.tsx, 90, 12)) +>props : Symbol(props, Decl(jsxElementType.tsx, 90, 23)) +>React : Symbol(React, Decl(jsxElementType.tsx, 1, 6)) +>ReactElement : Symbol(React.ReactElement, Decl(react16.d.ts, 135, 9)) +>Component : Symbol(Component, Decl(jsxElementType.tsx, 90, 62)) +>T : Symbol(T, Decl(jsxElementType.tsx, 90, 12)) + + return ; +>Component : Symbol(Component, Decl(jsxElementType.tsx, 90, 62)) +} + diff --git a/tests/baselines/reference/jsxElementType.types b/tests/baselines/reference/jsxElementType.types index 10b837eed65c3..6f7383944bfab 100644 --- a/tests/baselines/reference/jsxElementType.types +++ b/tests/baselines/reference/jsxElementType.types @@ -260,3 +260,15 @@ function ReactNativeFlatList( > : JSX.Element >ReactNativeFlatList : (props: {}, ref: React.ForwardedRef) => null +// testing higher-order component compat +function f1 React.ReactElement>(Component: T) { +>f1 : React.ReactElement>(Component: T) => JSX.Element +>props : {} +>React : any +>Component : T + + return ; +> : JSX.Element +>Component : T +} + diff --git a/tests/cases/compiler/jsxElementType.tsx b/tests/cases/compiler/jsxElementType.tsx index 6d8b0f5952446..fd0a07001b4ac 100644 --- a/tests/cases/compiler/jsxElementType.tsx +++ b/tests/cases/compiler/jsxElementType.tsx @@ -87,4 +87,9 @@ function ReactNativeFlatList( ) { return null; } -; \ No newline at end of file +; + +// testing higher-order component compat +function f1 React.ReactElement>(Component: T) { + return ; +} From 9adca32f66f190e7f8c57b2179d1f1a85bbb46a3 Mon Sep 17 00:00:00 2001 From: eps1lon Date: Thu, 13 Apr 2023 04:50:34 +0200 Subject: [PATCH 13/19] Drop the `getApparentType` it's cleaner --- src/compiler/checker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index f278dea9ecf96..d50d494131dbe 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -30867,7 +30867,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const tagType = isJsxIntrinsicIdentifier(jsxOpeningLikeNode.tagName) ? // TODO: Should this be a literal that library authors could potentially check against? stringType - : getApparentType(checkExpression(jsxOpeningLikeNode.tagName)); + : checkExpression(jsxOpeningLikeNode.tagName); checkTypeRelatedTo(tagType, elementTypeConstraint, assignableRelation, jsxOpeningLikeNode.tagName, Diagnostics.Its_type_0_is_not_a_valid_JSX_element_type, () => { const componentName = getTextOfNode(jsxOpeningLikeNode.tagName); return chainDiagnosticMessages(/*details*/ undefined, Diagnostics._0_cannot_be_used_as_a_JSX_component, componentName); From 68a73355db42acb8a02d85b1b3ce1b36acc7c93f Mon Sep 17 00:00:00 2001 From: eps1lon Date: Thu, 13 Apr 2023 04:54:06 +0200 Subject: [PATCH 14/19] my-web-component -> my-custom-element --- tests/baselines/reference/jsxElementType.errors.txt | 4 ++-- tests/baselines/reference/jsxElementType.js | 6 +++--- tests/baselines/reference/jsxElementType.symbols | 12 ++++++------ tests/baselines/reference/jsxElementType.types | 12 ++++++------ tests/cases/compiler/jsxElementType.tsx | 4 ++-- 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/tests/baselines/reference/jsxElementType.errors.txt b/tests/baselines/reference/jsxElementType.errors.txt index f8d4c778ac8c3..93af6e12f8295 100644 --- a/tests/baselines/reference/jsxElementType.errors.txt +++ b/tests/baselines/reference/jsxElementType.errors.txt @@ -57,7 +57,7 @@ tests/cases/compiler/jsxElementType.tsx(92,11): error TS2322: Type '{}' is not a namespace JSX { type ElementType = string | NewReactJSXElementConstructor; interface IntrinsicElements { - ['my-web-component']: React.DOMAttributes; + ['my-custom-element']: React.DOMAttributes; } } } @@ -154,7 +154,7 @@ tests/cases/compiler/jsxElementType.tsx(92,11): error TS2322: Type '{}' is not a // Host element types still work
; - ; + ; // Highlighting various ecosystem compat issues // react-native-gesture-handler diff --git a/tests/baselines/reference/jsxElementType.js b/tests/baselines/reference/jsxElementType.js index abe0115d1c0e4..c232b641bedab 100644 --- a/tests/baselines/reference/jsxElementType.js +++ b/tests/baselines/reference/jsxElementType.js @@ -23,7 +23,7 @@ declare global { namespace JSX { type ElementType = string | NewReactJSXElementConstructor; interface IntrinsicElements { - ['my-web-component']: React.DOMAttributes; + ['my-custom-element']: React.DOMAttributes; } } } @@ -74,7 +74,7 @@ Component = RenderStringClass; // Host element types still work
; -; +; // Highlighting various ecosystem compat issues // react-native-gesture-handler @@ -211,7 +211,7 @@ React.createElement(RenderStringClass, { title: "react" }); React.createElement(RenderStringClass, { excessProp: true }); // Host element types still work React.createElement("div", null); -React.createElement("my-web-component", null); +React.createElement("my-custom-element", null); function ReactNativeFlatList(props, ref) { return null; } diff --git a/tests/baselines/reference/jsxElementType.symbols b/tests/baselines/reference/jsxElementType.symbols index b9ce3572dd243..cec41515b1fac 100644 --- a/tests/baselines/reference/jsxElementType.symbols +++ b/tests/baselines/reference/jsxElementType.symbols @@ -61,9 +61,9 @@ declare global { interface IntrinsicElements { >IntrinsicElements : Symbol(IntrinsicElements, Decl(react16.d.ts, 2514, 86), Decl(jsxElementType.tsx, 22, 67)) - ['my-web-component']: React.DOMAttributes; ->['my-web-component'] : Symbol(IntrinsicElements['my-web-component'], Decl(jsxElementType.tsx, 23, 33)) ->'my-web-component' : Symbol(IntrinsicElements['my-web-component'], Decl(jsxElementType.tsx, 23, 33)) + ['my-custom-element']: React.DOMAttributes; +>['my-custom-element'] : Symbol(IntrinsicElements['my-custom-element'], Decl(jsxElementType.tsx, 23, 33)) +>'my-custom-element' : Symbol(IntrinsicElements['my-custom-element'], Decl(jsxElementType.tsx, 23, 33)) >React : Symbol(React, Decl(jsxElementType.tsx, 1, 6)) >DOMAttributes : Symbol(React.DOMAttributes, Decl(react16.d.ts, 844, 9)) } @@ -222,14 +222,14 @@ Component = RenderStringClass;
; >div : Symbol(JSX.IntrinsicElements.div, Decl(react16.d.ts, 2546, 114)) -; ->my-web-component : Symbol(JSX.IntrinsicElements['my-web-component'], Decl(jsxElementType.tsx, 23, 33)) +; +>my-custom-element : Symbol(JSX.IntrinsicElements['my-custom-element'], Decl(jsxElementType.tsx, 23, 33)) // Highlighting various ecosystem compat issues // react-native-gesture-handler // https://github.com/software-mansion/react-native-gesture-handler/blob/79017e5e7cc2e82e6467851f870920ff836ee04f/src/components/GestureComponents.tsx#L139-L146 interface ReactNativeFlatListProps {} ->ReactNativeFlatListProps : Symbol(ReactNativeFlatListProps, Decl(jsxElementType.tsx, 75, 21)) +>ReactNativeFlatListProps : Symbol(ReactNativeFlatListProps, Decl(jsxElementType.tsx, 75, 22)) >Item : Symbol(Item, Decl(jsxElementType.tsx, 80, 35)) function ReactNativeFlatList( diff --git a/tests/baselines/reference/jsxElementType.types b/tests/baselines/reference/jsxElementType.types index 6f7383944bfab..5116eae293aab 100644 --- a/tests/baselines/reference/jsxElementType.types +++ b/tests/baselines/reference/jsxElementType.types @@ -42,9 +42,9 @@ declare global { >ElementType : string | NewReactJSXElementConstructor interface IntrinsicElements { - ['my-web-component']: React.DOMAttributes; ->['my-web-component'] : React.DOMAttributes ->'my-web-component' : "my-web-component" + ['my-custom-element']: React.DOMAttributes; +>['my-custom-element'] : React.DOMAttributes +>'my-custom-element' : "my-custom-element" >React : any } } @@ -234,9 +234,9 @@ Component = RenderStringClass; >
: JSX.Element >div : any -; -> : JSX.Element ->my-web-component : any +; +> : JSX.Element +>my-custom-element : any // Highlighting various ecosystem compat issues // react-native-gesture-handler diff --git a/tests/cases/compiler/jsxElementType.tsx b/tests/cases/compiler/jsxElementType.tsx index fd0a07001b4ac..fd111fa74e90e 100644 --- a/tests/cases/compiler/jsxElementType.tsx +++ b/tests/cases/compiler/jsxElementType.tsx @@ -24,7 +24,7 @@ declare global { namespace JSX { type ElementType = string | NewReactJSXElementConstructor; interface IntrinsicElements { - ['my-web-component']: React.DOMAttributes; + ['my-custom-element']: React.DOMAttributes; } } } @@ -75,7 +75,7 @@ Component = RenderStringClass; // Host element types still work
; -; +; // Highlighting various ecosystem compat issues // react-native-gesture-handler From 320f52f680032e419a45d76b0e94848458abe3fe Mon Sep 17 00:00:00 2001 From: eps1lon Date: Thu, 13 Apr 2023 05:10:45 +0200 Subject: [PATCH 15/19] Add test for unknown host elements --- .../reference/jsxElementType.errors.txt | 15 ++++++++-- tests/baselines/reference/jsxElementType.js | 6 ++++ .../reference/jsxElementType.symbols | 30 +++++++++++-------- .../baselines/reference/jsxElementType.types | 9 ++++++ tests/cases/compiler/jsxElementType.tsx | 3 ++ 5 files changed, 47 insertions(+), 16 deletions(-) diff --git a/tests/baselines/reference/jsxElementType.errors.txt b/tests/baselines/reference/jsxElementType.errors.txt index 93af6e12f8295..1dc22375926c3 100644 --- a/tests/baselines/reference/jsxElementType.errors.txt +++ b/tests/baselines/reference/jsxElementType.errors.txt @@ -25,14 +25,16 @@ tests/cases/compiler/jsxElementType.tsx(72,20): error TS2769: No overload matche Overload 2 of 2, '(props: { title: string; }, context?: any): RenderStringClass', gave the following error. Type '{ excessProp: true; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes & Readonly<{ children?: ReactNode; }> & Readonly<{ title: string; }>'. Property 'excessProp' does not exist on type 'IntrinsicAttributes & IntrinsicClassAttributes & Readonly<{ children?: ReactNode; }> & Readonly<{ title: string; }>'. -tests/cases/compiler/jsxElementType.tsx(88,2): error TS2786: 'ReactNativeFlatList' cannot be used as a JSX component. +tests/cases/compiler/jsxElementType.tsx(78,1): error TS2339: Property 'boop' does not exist on type 'JSX.IntrinsicElements'. +tests/cases/compiler/jsxElementType.tsx(79,1): error TS2339: Property 'my-undeclared-custom-element' does not exist on type 'JSX.IntrinsicElements'. +tests/cases/compiler/jsxElementType.tsx(91,2): error TS2786: 'ReactNativeFlatList' cannot be used as a JSX component. Its type '(props: {}, ref: ForwardedRef) => null' is not a valid JSX element type. Type '(props: {}, ref: ForwardedRef) => null' is not assignable to type '(props: any) => React18ReactNode'. Target signature provides too few arguments. Expected 2 or more, but got 1. -tests/cases/compiler/jsxElementType.tsx(92,11): error TS2322: Type '{}' is not assignable to type 'LibraryManagedAttributes'. +tests/cases/compiler/jsxElementType.tsx(95,11): error TS2322: Type '{}' is not assignable to type 'LibraryManagedAttributes'. -==== tests/cases/compiler/jsxElementType.tsx (14 errors) ==== +==== tests/cases/compiler/jsxElementType.tsx (16 errors) ==== /// import * as React from "react"; @@ -155,6 +157,13 @@ tests/cases/compiler/jsxElementType.tsx(92,11): error TS2322: Type '{}' is not a // Host element types still work
; ; + // Undeclared host element types are still rejected + ; + ~~~~~~~~ +!!! error TS2339: Property 'boop' does not exist on type 'JSX.IntrinsicElements'. + ; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2339: Property 'my-undeclared-custom-element' does not exist on type 'JSX.IntrinsicElements'. // Highlighting various ecosystem compat issues // react-native-gesture-handler diff --git a/tests/baselines/reference/jsxElementType.js b/tests/baselines/reference/jsxElementType.js index c232b641bedab..e5755ab5d7e45 100644 --- a/tests/baselines/reference/jsxElementType.js +++ b/tests/baselines/reference/jsxElementType.js @@ -75,6 +75,9 @@ Component = RenderStringClass; // Host element types still work
; ; +// Undeclared host element types are still rejected +; +; // Highlighting various ecosystem compat issues // react-native-gesture-handler @@ -212,6 +215,9 @@ React.createElement(RenderStringClass, { excessProp: true }); // Host element types still work React.createElement("div", null); React.createElement("my-custom-element", null); +// Undeclared host element types are still rejected +React.createElement("boop", null); +React.createElement("my-undeclared-custom-element", null); function ReactNativeFlatList(props, ref) { return null; } diff --git a/tests/baselines/reference/jsxElementType.symbols b/tests/baselines/reference/jsxElementType.symbols index cec41515b1fac..d1379068f9b38 100644 --- a/tests/baselines/reference/jsxElementType.symbols +++ b/tests/baselines/reference/jsxElementType.symbols @@ -225,42 +225,46 @@ Component = RenderStringClass; ; >my-custom-element : Symbol(JSX.IntrinsicElements['my-custom-element'], Decl(jsxElementType.tsx, 23, 33)) +// Undeclared host element types are still rejected +; +; + // Highlighting various ecosystem compat issues // react-native-gesture-handler // https://github.com/software-mansion/react-native-gesture-handler/blob/79017e5e7cc2e82e6467851f870920ff836ee04f/src/components/GestureComponents.tsx#L139-L146 interface ReactNativeFlatListProps {} ->ReactNativeFlatListProps : Symbol(ReactNativeFlatListProps, Decl(jsxElementType.tsx, 75, 22)) ->Item : Symbol(Item, Decl(jsxElementType.tsx, 80, 35)) +>ReactNativeFlatListProps : Symbol(ReactNativeFlatListProps, Decl(jsxElementType.tsx, 78, 33)) +>Item : Symbol(Item, Decl(jsxElementType.tsx, 83, 35)) function ReactNativeFlatList( ->ReactNativeFlatList : Symbol(ReactNativeFlatList, Decl(jsxElementType.tsx, 80, 43)) +>ReactNativeFlatList : Symbol(ReactNativeFlatList, Decl(jsxElementType.tsx, 83, 43)) props: {}, ->props : Symbol(props, Decl(jsxElementType.tsx, 81, 29)) +>props : Symbol(props, Decl(jsxElementType.tsx, 84, 29)) ref: React.ForwardedRef ->ref : Symbol(ref, Decl(jsxElementType.tsx, 82, 12)) +>ref : Symbol(ref, Decl(jsxElementType.tsx, 85, 12)) >React : Symbol(React, Decl(jsxElementType.tsx, 1, 6)) >ForwardedRef : Symbol(React.ForwardedRef, Decl(react16.d.ts, 2355, 9)) ->ReactNativeFlatList : Symbol(ReactNativeFlatList, Decl(jsxElementType.tsx, 80, 43)) +>ReactNativeFlatList : Symbol(ReactNativeFlatList, Decl(jsxElementType.tsx, 83, 43)) ) { return null; } ; ->ReactNativeFlatList : Symbol(ReactNativeFlatList, Decl(jsxElementType.tsx, 80, 43)) +>ReactNativeFlatList : Symbol(ReactNativeFlatList, Decl(jsxElementType.tsx, 83, 43)) // testing higher-order component compat function f1 React.ReactElement>(Component: T) { ->f1 : Symbol(f1, Decl(jsxElementType.tsx, 87, 24)) ->T : Symbol(T, Decl(jsxElementType.tsx, 90, 12)) ->props : Symbol(props, Decl(jsxElementType.tsx, 90, 23)) +>f1 : Symbol(f1, Decl(jsxElementType.tsx, 90, 24)) +>T : Symbol(T, Decl(jsxElementType.tsx, 93, 12)) +>props : Symbol(props, Decl(jsxElementType.tsx, 93, 23)) >React : Symbol(React, Decl(jsxElementType.tsx, 1, 6)) >ReactElement : Symbol(React.ReactElement, Decl(react16.d.ts, 135, 9)) ->Component : Symbol(Component, Decl(jsxElementType.tsx, 90, 62)) ->T : Symbol(T, Decl(jsxElementType.tsx, 90, 12)) +>Component : Symbol(Component, Decl(jsxElementType.tsx, 93, 62)) +>T : Symbol(T, Decl(jsxElementType.tsx, 93, 12)) return ; ->Component : Symbol(Component, Decl(jsxElementType.tsx, 90, 62)) +>Component : Symbol(Component, Decl(jsxElementType.tsx, 93, 62)) } diff --git a/tests/baselines/reference/jsxElementType.types b/tests/baselines/reference/jsxElementType.types index 5116eae293aab..2c005aaa6bc1b 100644 --- a/tests/baselines/reference/jsxElementType.types +++ b/tests/baselines/reference/jsxElementType.types @@ -238,6 +238,15 @@ Component = RenderStringClass; > : JSX.Element >my-custom-element : any +// Undeclared host element types are still rejected +; +> : JSX.Element +>boop : any + +; +> : JSX.Element +>my-undeclared-custom-element : any + // Highlighting various ecosystem compat issues // react-native-gesture-handler // https://github.com/software-mansion/react-native-gesture-handler/blob/79017e5e7cc2e82e6467851f870920ff836ee04f/src/components/GestureComponents.tsx#L139-L146 diff --git a/tests/cases/compiler/jsxElementType.tsx b/tests/cases/compiler/jsxElementType.tsx index fd111fa74e90e..f2ce78bf05306 100644 --- a/tests/cases/compiler/jsxElementType.tsx +++ b/tests/cases/compiler/jsxElementType.tsx @@ -76,6 +76,9 @@ Component = RenderStringClass; // Host element types still work
; ; +// Undeclared host element types are still rejected +; +; // Highlighting various ecosystem compat issues // react-native-gesture-handler From 79c22f99a1058c22eb2082262aecce79a4c39b55 Mon Sep 17 00:00:00 2001 From: eps1lon Date: Thu, 13 Apr 2023 05:11:25 +0200 Subject: [PATCH 16/19] Use literal type instead of abstract string --- src/compiler/checker.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index d50d494131dbe..f2f965770b6b3 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -30322,7 +30322,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { /** * Returns true iff React would emit this tag name as a string rather than an identifier or qualified name */ - function isJsxIntrinsicIdentifier(tagName: JsxTagNameExpression): boolean { + function isJsxIntrinsicIdentifier(tagName: JsxTagNameExpression): tagName is Identifier { return tagName.kind === SyntaxKind.Identifier && isIntrinsicJsxName(tagName.escapedText); } @@ -30864,12 +30864,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const elementTypeConstraint = getJsxElementTypeTypeAt(jsxOpeningLikeNode); if (elementTypeConstraint !== undefined) { - const tagType = isJsxIntrinsicIdentifier(jsxOpeningLikeNode.tagName) - ? // TODO: Should this be a literal that library authors could potentially check against? - stringType - : checkExpression(jsxOpeningLikeNode.tagName); - checkTypeRelatedTo(tagType, elementTypeConstraint, assignableRelation, jsxOpeningLikeNode.tagName, Diagnostics.Its_type_0_is_not_a_valid_JSX_element_type, () => { - const componentName = getTextOfNode(jsxOpeningLikeNode.tagName); + const tagName = jsxOpeningLikeNode.tagName; + const tagType = isJsxIntrinsicIdentifier(tagName) + ? getStringLiteralType(tagName.escapedText as string) + : checkExpression(tagName); + checkTypeRelatedTo(tagType, elementTypeConstraint, assignableRelation, tagName, Diagnostics.Its_type_0_is_not_a_valid_JSX_element_type, () => { + const componentName = getTextOfNode(tagName); return chainDiagnosticMessages(/*details*/ undefined, Diagnostics._0_cannot_be_used_as_a_JSX_component, componentName); }); } From 14bd3fd9796abe6620c1bb1830f743a219f7cb26 Mon Sep 17 00:00:00 2001 From: eps1lon Date: Thu, 13 Apr 2023 05:15:56 +0200 Subject: [PATCH 17/19] Unresolved element types are still rejected --- tests/baselines/reference/jsxElementType.errors.txt | 11 ++++++++++- tests/baselines/reference/jsxElementType.js | 5 +++++ tests/baselines/reference/jsxElementType.symbols | 4 ++++ tests/baselines/reference/jsxElementType.types | 9 +++++++++ tests/cases/compiler/jsxElementType.tsx | 3 +++ 5 files changed, 31 insertions(+), 1 deletion(-) diff --git a/tests/baselines/reference/jsxElementType.errors.txt b/tests/baselines/reference/jsxElementType.errors.txt index 1dc22375926c3..ddd2efe19cce7 100644 --- a/tests/baselines/reference/jsxElementType.errors.txt +++ b/tests/baselines/reference/jsxElementType.errors.txt @@ -32,9 +32,11 @@ tests/cases/compiler/jsxElementType.tsx(91,2): error TS2786: 'ReactNativeFlatLis Type '(props: {}, ref: ForwardedRef) => null' is not assignable to type '(props: any) => React18ReactNode'. Target signature provides too few arguments. Expected 2 or more, but got 1. tests/cases/compiler/jsxElementType.tsx(95,11): error TS2322: Type '{}' is not assignable to type 'LibraryManagedAttributes'. +tests/cases/compiler/jsxElementType.tsx(98,2): error TS2304: Cannot find name 'Unresolved'. +tests/cases/compiler/jsxElementType.tsx(99,2): error TS2304: Cannot find name 'Unresolved'. -==== tests/cases/compiler/jsxElementType.tsx (16 errors) ==== +==== tests/cases/compiler/jsxElementType.tsx (18 errors) ==== /// import * as React from "react"; @@ -188,4 +190,11 @@ tests/cases/compiler/jsxElementType.tsx(95,11): error TS2322: Type '{}' is not a ~~~~~~~~~ !!! error TS2322: Type '{}' is not assignable to type 'LibraryManagedAttributes'. } + + ; + ~~~~~~~~~~ +!!! error TS2304: Cannot find name 'Unresolved'. + ; + ~~~~~~~~~~ +!!! error TS2304: Cannot find name 'Unresolved'. \ No newline at end of file diff --git a/tests/baselines/reference/jsxElementType.js b/tests/baselines/reference/jsxElementType.js index e5755ab5d7e45..13986b0c62e90 100644 --- a/tests/baselines/reference/jsxElementType.js +++ b/tests/baselines/reference/jsxElementType.js @@ -95,6 +95,9 @@ function ReactNativeFlatList( function f1 React.ReactElement>(Component: T) { return ; } + +; +; //// [jsxElementType.js] @@ -226,3 +229,5 @@ React.createElement(ReactNativeFlatList, null); function f1(Component) { return React.createElement(Component, null); } +React.createElement(Unresolved, null); +React.createElement(Unresolved, { foo: "abc" }); diff --git a/tests/baselines/reference/jsxElementType.symbols b/tests/baselines/reference/jsxElementType.symbols index d1379068f9b38..c932009d84a1f 100644 --- a/tests/baselines/reference/jsxElementType.symbols +++ b/tests/baselines/reference/jsxElementType.symbols @@ -268,3 +268,7 @@ function f1 React.ReactElement>(Component: T) { >Component : Symbol(Component, Decl(jsxElementType.tsx, 93, 62)) } +; +; +>foo : Symbol(foo, Decl(jsxElementType.tsx, 98, 11)) + diff --git a/tests/baselines/reference/jsxElementType.types b/tests/baselines/reference/jsxElementType.types index 2c005aaa6bc1b..4e9a5a9a8ccb6 100644 --- a/tests/baselines/reference/jsxElementType.types +++ b/tests/baselines/reference/jsxElementType.types @@ -281,3 +281,12 @@ function f1 React.ReactElement>(Component: T) { >Component : T } +; +> : JSX.Element +>Unresolved : any + +; +> : JSX.Element +>Unresolved : any +>foo : string + diff --git a/tests/cases/compiler/jsxElementType.tsx b/tests/cases/compiler/jsxElementType.tsx index f2ce78bf05306..75585a2d99a43 100644 --- a/tests/cases/compiler/jsxElementType.tsx +++ b/tests/cases/compiler/jsxElementType.tsx @@ -96,3 +96,6 @@ function ReactNativeFlatList( function f1 React.ReactElement>(Component: T) { return ; } + +; +; From b7a552e32e11a5e4e2cd737f7ba060985ede0fdc Mon Sep 17 00:00:00 2001 From: eps1lon Date: Fri, 14 Apr 2023 14:46:14 +0200 Subject: [PATCH 18/19] Unescape tag name for literal type --- src/compiler/checker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 2049c7dc5b2e8..dafa64f066d7f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -30872,7 +30872,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (elementTypeConstraint !== undefined) { const tagName = jsxOpeningLikeNode.tagName; const tagType = isJsxIntrinsicIdentifier(tagName) - ? getStringLiteralType(tagName.escapedText as string) + ? getStringLiteralType(unescapeLeadingUnderscores(tagName.escapedText)) : checkExpression(tagName); checkTypeRelatedTo(tagType, elementTypeConstraint, assignableRelation, tagName, Diagnostics.Its_type_0_is_not_a_valid_JSX_element_type, () => { const componentName = getTextOfNode(tagName); From d02bc6140780e4a1a045fd8f50f2a7f4ac4c3db7 Mon Sep 17 00:00:00 2001 From: eps1lon Date: Fri, 14 Apr 2023 14:48:00 +0200 Subject: [PATCH 19/19] Add Preact inspired test --- .../jsxElementTypeLiteral.errors.txt | 37 +++++++++++++++++++ .../reference/jsxElementTypeLiteral.js | 35 ++++++++++++++++++ .../reference/jsxElementTypeLiteral.symbols | 33 +++++++++++++++++ .../reference/jsxElementTypeLiteral.types | 35 ++++++++++++++++++ .../cases/compiler/jsxElementTypeLiteral.tsx | 22 +++++++++++ 5 files changed, 162 insertions(+) create mode 100644 tests/baselines/reference/jsxElementTypeLiteral.errors.txt create mode 100644 tests/baselines/reference/jsxElementTypeLiteral.js create mode 100644 tests/baselines/reference/jsxElementTypeLiteral.symbols create mode 100644 tests/baselines/reference/jsxElementTypeLiteral.types create mode 100644 tests/cases/compiler/jsxElementTypeLiteral.tsx diff --git a/tests/baselines/reference/jsxElementTypeLiteral.errors.txt b/tests/baselines/reference/jsxElementTypeLiteral.errors.txt new file mode 100644 index 0000000000000..942df5ad7c5a9 --- /dev/null +++ b/tests/baselines/reference/jsxElementTypeLiteral.errors.txt @@ -0,0 +1,37 @@ +tests/cases/compiler/jsxElementTypeLiteral.tsx(16,10): error TS2786: 'span' cannot be used as a JSX component. + Its type '"span"' is not a valid JSX element type. +tests/cases/compiler/jsxElementTypeLiteral.tsx(20,9): error TS2339: Property 'ruhroh' does not exist on type 'JSX.IntrinsicElements'. +tests/cases/compiler/jsxElementTypeLiteral.tsx(20,10): error TS2786: 'ruhroh' cannot be used as a JSX component. + Its type '"ruhroh"' is not a valid JSX element type. + + +==== tests/cases/compiler/jsxElementTypeLiteral.tsx (3 errors) ==== + /// + import * as React from "react"; + + declare global { + namespace JSX { + // This should only use keys of JSX.IntrinsicElements. + // Diverging here to illustrate different error messages. + type ElementType = "div"; + } + } + + // should be fine - `ElementType` accepts `div` + let a =
; + + // should be an error - `ElementType` does not accept `span` + let b = ; + ~~~~ +!!! error TS2786: 'span' cannot be used as a JSX component. +!!! error TS2786: Its type '"span"' is not a valid JSX element type. + + // Should be an error. + // `ruhroh` is in neither `IntrinsicElements` nor `ElementType` + let c = ; + ~~~~~~~~~~ +!!! error TS2339: Property 'ruhroh' does not exist on type 'JSX.IntrinsicElements'. + ~~~~~~ +!!! error TS2786: 'ruhroh' cannot be used as a JSX component. +!!! error TS2786: Its type '"ruhroh"' is not a valid JSX element type. + \ No newline at end of file diff --git a/tests/baselines/reference/jsxElementTypeLiteral.js b/tests/baselines/reference/jsxElementTypeLiteral.js new file mode 100644 index 0000000000000..95472a281f0e1 --- /dev/null +++ b/tests/baselines/reference/jsxElementTypeLiteral.js @@ -0,0 +1,35 @@ +//// [jsxElementTypeLiteral.tsx] +/// +import * as React from "react"; + +declare global { + namespace JSX { + // This should only use keys of JSX.IntrinsicElements. + // Diverging here to illustrate different error messages. + type ElementType = "div"; + } +} + +// should be fine - `ElementType` accepts `div` +let a =
; + +// should be an error - `ElementType` does not accept `span` +let b = ; + +// Should be an error. +// `ruhroh` is in neither `IntrinsicElements` nor `ElementType` +let c = ; + + +//// [jsxElementTypeLiteral.js] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +/// +var React = require("react"); +// should be fine - `ElementType` accepts `div` +var a = React.createElement("div", null); +// should be an error - `ElementType` does not accept `span` +var b = React.createElement("span", null); +// Should be an error. +// `ruhroh` is in neither `IntrinsicElements` nor `ElementType` +var c = React.createElement("ruhroh", null); diff --git a/tests/baselines/reference/jsxElementTypeLiteral.symbols b/tests/baselines/reference/jsxElementTypeLiteral.symbols new file mode 100644 index 0000000000000..ffd61d8a345b1 --- /dev/null +++ b/tests/baselines/reference/jsxElementTypeLiteral.symbols @@ -0,0 +1,33 @@ +=== tests/cases/compiler/jsxElementTypeLiteral.tsx === +/// +import * as React from "react"; +>React : Symbol(React, Decl(jsxElementTypeLiteral.tsx, 1, 6)) + +declare global { +>global : Symbol(global, Decl(jsxElementTypeLiteral.tsx, 1, 31)) + + namespace JSX { +>JSX : Symbol(JSX, Decl(react16.d.ts, 2493, 12), Decl(jsxElementTypeLiteral.tsx, 3, 16)) + + // This should only use keys of JSX.IntrinsicElements. + // Diverging here to illustrate different error messages. + type ElementType = "div"; +>ElementType : Symbol(ElementType, Decl(jsxElementTypeLiteral.tsx, 4, 17)) + } +} + +// should be fine - `ElementType` accepts `div` +let a =
; +>a : Symbol(a, Decl(jsxElementTypeLiteral.tsx, 12, 3)) +>div : Symbol(JSX.IntrinsicElements.div, Decl(react16.d.ts, 2546, 114)) + +// should be an error - `ElementType` does not accept `span` +let b = ; +>b : Symbol(b, Decl(jsxElementTypeLiteral.tsx, 15, 3)) +>span : Symbol(JSX.IntrinsicElements.span, Decl(react16.d.ts, 2609, 114)) + +// Should be an error. +// `ruhroh` is in neither `IntrinsicElements` nor `ElementType` +let c = ; +>c : Symbol(c, Decl(jsxElementTypeLiteral.tsx, 19, 3)) + diff --git a/tests/baselines/reference/jsxElementTypeLiteral.types b/tests/baselines/reference/jsxElementTypeLiteral.types new file mode 100644 index 0000000000000..998c4e8dbeb6c --- /dev/null +++ b/tests/baselines/reference/jsxElementTypeLiteral.types @@ -0,0 +1,35 @@ +=== tests/cases/compiler/jsxElementTypeLiteral.tsx === +/// +import * as React from "react"; +>React : typeof React + +declare global { +>global : any + + namespace JSX { + // This should only use keys of JSX.IntrinsicElements. + // Diverging here to illustrate different error messages. + type ElementType = "div"; +>ElementType : "div" + } +} + +// should be fine - `ElementType` accepts `div` +let a =
; +>a : JSX.Element +>
: JSX.Element +>div : any + +// should be an error - `ElementType` does not accept `span` +let b = ; +>b : JSX.Element +> : JSX.Element +>span : any + +// Should be an error. +// `ruhroh` is in neither `IntrinsicElements` nor `ElementType` +let c = ; +>c : JSX.Element +> : JSX.Element +>ruhroh : any + diff --git a/tests/cases/compiler/jsxElementTypeLiteral.tsx b/tests/cases/compiler/jsxElementTypeLiteral.tsx new file mode 100644 index 0000000000000..79c3b0e15767e --- /dev/null +++ b/tests/cases/compiler/jsxElementTypeLiteral.tsx @@ -0,0 +1,22 @@ +// @strict: true +// @jsx: react +/// +import * as React from "react"; + +declare global { + namespace JSX { + // This should only use keys of JSX.IntrinsicElements. + // Diverging here to illustrate different error messages. + type ElementType = "div"; + } +} + +// should be fine - `ElementType` accepts `div` +let a =
; + +// should be an error - `ElementType` does not accept `span` +let b = ; + +// Should be an error. +// `ruhroh` is in neither `IntrinsicElements` nor `ElementType` +let c = ;