diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 7d940cf747ee8..01b93f5800b6d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -29620,18 +29620,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getJsxManagedAttributesFromLocatedAttributes(context: JsxOpeningLikeElement, ns: Symbol, attributesType: Type) { const managedSym = getJsxLibraryManagedAttributes(ns); if (managedSym) { - const declaredManagedType = getDeclaredTypeOfSymbol(managedSym); // fetches interface type, or initializes symbol links type parmaeters const ctorType = getStaticTypeOfReferencedJsxConstructor(context); - if (managedSym.flags & SymbolFlags.TypeAlias) { - const params = getSymbolLinks(managedSym).typeParameters; - if (length(params) >= 2) { - const args = fillMissingTypeArguments([ctorType, attributesType], params, 2, isInJSFile(context)); - return getTypeAliasInstantiation(managedSym, args); - } - } - if (length((declaredManagedType as GenericType).typeParameters) >= 2) { - const args = fillMissingTypeArguments([ctorType, attributesType], (declaredManagedType as GenericType).typeParameters, 2, isInJSFile(context)); - return createTypeReference((declaredManagedType as GenericType), args); + const result = instantiateAliasOrInterfaceWithDefaults(managedSym, isInJSFile(context), ctorType, attributesType); + if (result) { + return result; } } return attributesType; @@ -30690,6 +30682,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return jsxNamespace && getSymbol(jsxNamespace.exports!, JsxNames.LibraryManagedAttributes, SymbolFlags.Type); } + function getJsxElementTypeSymbol(jsxNamespace: Symbol) { + // JSX.ElementType [symbol] + return jsxNamespace && getSymbol(jsxNamespace.exports!, JsxNames.ElementType, SymbolFlags.Type); + } + /// e.g. "props" for React.d.ts, /// or 'undefined' if ElementAttributesProperty doesn't exist (which means all /// non-intrinsic elements' attributes type is 'any'), @@ -30826,11 +30823,31 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getJsxElementTypeTypeAt(location: Node): Type | undefined { - const type = getJsxType(JsxNames.ElementType, location); - if (isErrorType(type)) return undefined; + const ns = getJsxNamespaceAt(location); + if (!ns) return undefined; + const sym = getJsxElementTypeSymbol(ns); + if (!sym) return undefined; + const type = instantiateAliasOrInterfaceWithDefaults(sym, isInJSFile(location)); + if (!type || isErrorType(type)) return undefined; return type; } + function instantiateAliasOrInterfaceWithDefaults(managedSym: Symbol, inJs: boolean, ...typeArguments: Type[]) { + const declaredManagedType = getDeclaredTypeOfSymbol(managedSym); // fetches interface type, or initializes symbol links type parmaeters + if (managedSym.flags & SymbolFlags.TypeAlias) { + const params = getSymbolLinks(managedSym).typeParameters; + if (length(params) >= typeArguments.length) { + const args = fillMissingTypeArguments(typeArguments, params, typeArguments.length, inJs); + return length(args) === 0 ? declaredManagedType : getTypeAliasInstantiation(managedSym, args); + } + } + if (length((declaredManagedType as GenericType).typeParameters) >= typeArguments.length) { + const args = fillMissingTypeArguments(typeArguments, (declaredManagedType as GenericType).typeParameters, typeArguments.length, inJs); + return createTypeReference((declaredManagedType as GenericType), args); + } + return undefined; + } + /** * Returns all the properties of the Jsx.IntrinsicElements interface */ diff --git a/tests/baselines/reference/jsxElementTypeLiteralWithGeneric.errors.txt b/tests/baselines/reference/jsxElementTypeLiteralWithGeneric.errors.txt new file mode 100644 index 0000000000000..b710331de39d9 --- /dev/null +++ b/tests/baselines/reference/jsxElementTypeLiteralWithGeneric.errors.txt @@ -0,0 +1,33 @@ +tests/cases/compiler/jsxElementTypeLiteralWithGeneric.tsx(21,9): error TS2339: Property 'ruhroh' does not exist on type 'JSX.IntrinsicElements'. +tests/cases/compiler/jsxElementTypeLiteralWithGeneric.tsx(21,10): error TS2786: 'ruhroh' cannot be used as a JSX component. + Its type '"ruhroh"' is not a valid JSX element type. + + +==== tests/cases/compiler/jsxElementTypeLiteralWithGeneric.tsx (2 errors) ==== + /// + import * as React from "react"; + + declare global { + namespace JSX { + type ElementType

= + | { + [K in keyof JSX.IntrinsicElements]: P extends JSX.IntrinsicElements[K] + ? K + : never; + }[keyof JSX.IntrinsicElements] + | React.ComponentType

; + } + } + + // should be fine - `ElementType` accepts `div` + let a =

; + + // 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/jsxElementTypeLiteralWithGeneric.js b/tests/baselines/reference/jsxElementTypeLiteralWithGeneric.js new file mode 100644 index 0000000000000..56c43f8e1378e --- /dev/null +++ b/tests/baselines/reference/jsxElementTypeLiteralWithGeneric.js @@ -0,0 +1,34 @@ +//// [jsxElementTypeLiteralWithGeneric.tsx] +/// +import * as React from "react"; + +declare global { + namespace JSX { + type ElementType

= + | { + [K in keyof JSX.IntrinsicElements]: P extends JSX.IntrinsicElements[K] + ? K + : never; + }[keyof JSX.IntrinsicElements] + | React.ComponentType

; + } +} + +// should be fine - `ElementType` accepts `div` +let a =

; + +// Should be an error. +// `ruhroh` is in neither `IntrinsicElements` nor `ElementType` +let c = ; + + +//// [jsxElementTypeLiteralWithGeneric.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. +// `ruhroh` is in neither `IntrinsicElements` nor `ElementType` +var c = React.createElement("ruhroh", null); diff --git a/tests/baselines/reference/jsxElementTypeLiteralWithGeneric.symbols b/tests/baselines/reference/jsxElementTypeLiteralWithGeneric.symbols new file mode 100644 index 0000000000000..3bfc9dd033791 --- /dev/null +++ b/tests/baselines/reference/jsxElementTypeLiteralWithGeneric.symbols @@ -0,0 +1,50 @@ +=== tests/cases/compiler/jsxElementTypeLiteralWithGeneric.tsx === +/// +import * as React from "react"; +>React : Symbol(React, Decl(jsxElementTypeLiteralWithGeneric.tsx, 1, 6)) + +declare global { +>global : Symbol(global, Decl(jsxElementTypeLiteralWithGeneric.tsx, 1, 31)) + + namespace JSX { +>JSX : Symbol(JSX, Decl(react16.d.ts, 2493, 12), Decl(jsxElementTypeLiteralWithGeneric.tsx, 3, 16)) + + type ElementType

= +>ElementType : Symbol(ElementType, Decl(jsxElementTypeLiteralWithGeneric.tsx, 4, 17)) +>P : Symbol(P, Decl(jsxElementTypeLiteralWithGeneric.tsx, 5, 21)) + + | { + [K in keyof JSX.IntrinsicElements]: P extends JSX.IntrinsicElements[K] +>K : Symbol(K, Decl(jsxElementTypeLiteralWithGeneric.tsx, 7, 9)) +>JSX : Symbol(JSX, Decl(react16.d.ts, 2493, 12), Decl(jsxElementTypeLiteralWithGeneric.tsx, 3, 16)) +>IntrinsicElements : Symbol(IntrinsicElements, Decl(react16.d.ts, 2514, 86)) +>P : Symbol(P, Decl(jsxElementTypeLiteralWithGeneric.tsx, 5, 21)) +>JSX : Symbol(JSX, Decl(react16.d.ts, 2493, 12), Decl(jsxElementTypeLiteralWithGeneric.tsx, 3, 16)) +>IntrinsicElements : Symbol(IntrinsicElements, Decl(react16.d.ts, 2514, 86)) +>K : Symbol(K, Decl(jsxElementTypeLiteralWithGeneric.tsx, 7, 9)) + + ? K +>K : Symbol(K, Decl(jsxElementTypeLiteralWithGeneric.tsx, 7, 9)) + + : never; + }[keyof JSX.IntrinsicElements] +>JSX : Symbol(JSX, Decl(react16.d.ts, 2493, 12), Decl(jsxElementTypeLiteralWithGeneric.tsx, 3, 16)) +>IntrinsicElements : Symbol(IntrinsicElements, Decl(react16.d.ts, 2514, 86)) + + | React.ComponentType

; +>React : Symbol(React, Decl(jsxElementTypeLiteralWithGeneric.tsx, 1, 6)) +>ComponentType : Symbol(React.ComponentType, Decl(react16.d.ts, 117, 60)) +>P : Symbol(P, Decl(jsxElementTypeLiteralWithGeneric.tsx, 5, 21)) + } +} + +// should be fine - `ElementType` accepts `div` +let a =

; +>a : Symbol(a, Decl(jsxElementTypeLiteralWithGeneric.tsx, 16, 3)) +>div : Symbol(JSX.IntrinsicElements.div, Decl(react16.d.ts, 2546, 114)) + +// Should be an error. +// `ruhroh` is in neither `IntrinsicElements` nor `ElementType` +let c = ; +>c : Symbol(c, Decl(jsxElementTypeLiteralWithGeneric.tsx, 20, 3)) + diff --git a/tests/baselines/reference/jsxElementTypeLiteralWithGeneric.types b/tests/baselines/reference/jsxElementTypeLiteralWithGeneric.types new file mode 100644 index 0000000000000..f152db4d3a009 --- /dev/null +++ b/tests/baselines/reference/jsxElementTypeLiteralWithGeneric.types @@ -0,0 +1,40 @@ +=== tests/cases/compiler/jsxElementTypeLiteralWithGeneric.tsx === +/// +import * as React from "react"; +>React : typeof React + +declare global { +>global : any + + namespace JSX { + type ElementType

= +>ElementType : ElementType

+ + | { + [K in keyof JSX.IntrinsicElements]: P extends JSX.IntrinsicElements[K] +>JSX : any +>JSX : any + + ? K + : never; + }[keyof JSX.IntrinsicElements] +>JSX : any + + | React.ComponentType

; +>React : any + } +} + +// should be fine - `ElementType` accepts `div` +let a =

; +>a : JSX.Element +>
: JSX.Element +>div : 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/jsxElementTypeLiteralWithGeneric.tsx b/tests/cases/compiler/jsxElementTypeLiteralWithGeneric.tsx new file mode 100644 index 0000000000000..936608092d902 --- /dev/null +++ b/tests/cases/compiler/jsxElementTypeLiteralWithGeneric.tsx @@ -0,0 +1,23 @@ +// @strict: true +// @jsx: react +/// +import * as React from "react"; + +declare global { + namespace JSX { + type ElementType

= + | { + [K in keyof JSX.IntrinsicElements]: P extends JSX.IntrinsicElements[K] + ? K + : never; + }[keyof JSX.IntrinsicElements] + | React.ComponentType

; + } +} + +// should be fine - `ElementType` accepts `div` +let a =

; + +// Should be an error. +// `ruhroh` is in neither `IntrinsicElements` nor `ElementType` +let c = ;