Instantiate generic ElementType declarations (#53943)

This commit is contained in:
Wesley Wigham 2023-04-24 13:25:39 -07:00 committed by GitHub
parent 8749fb5c0a
commit a177af1cc8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 210 additions and 13 deletions

View File

@ -29635,18 +29635,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;
@ -30705,6 +30697,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'),
@ -30841,11 +30838,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
*/

View File

@ -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) ====
/// <reference path="/.lib/react16.d.ts" />
import * as React from "react";
declare global {
namespace JSX {
type ElementType<P = any> =
| {
[K in keyof JSX.IntrinsicElements]: P extends JSX.IntrinsicElements[K]
? K
: never;
}[keyof JSX.IntrinsicElements]
| React.ComponentType<P>;
}
}
// should be fine - `ElementType` accepts `div`
let a = <div />;
// Should be an error.
// `ruhroh` is in neither `IntrinsicElements` nor `ElementType`
let c = <ruhroh />;
~~~~~~~~~~
!!! 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.

View File

@ -0,0 +1,34 @@
//// [jsxElementTypeLiteralWithGeneric.tsx]
/// <reference path="/.lib/react16.d.ts" />
import * as React from "react";
declare global {
namespace JSX {
type ElementType<P = any> =
| {
[K in keyof JSX.IntrinsicElements]: P extends JSX.IntrinsicElements[K]
? K
: never;
}[keyof JSX.IntrinsicElements]
| React.ComponentType<P>;
}
}
// should be fine - `ElementType` accepts `div`
let a = <div />;
// Should be an error.
// `ruhroh` is in neither `IntrinsicElements` nor `ElementType`
let c = <ruhroh />;
//// [jsxElementTypeLiteralWithGeneric.js]
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/// <reference path="react16.d.ts" />
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);

View File

@ -0,0 +1,50 @@
=== tests/cases/compiler/jsxElementTypeLiteralWithGeneric.tsx ===
/// <reference path="react16.d.ts" />
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<P = any> =
>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<P>;
>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 = <div />;
>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 = <ruhroh />;
>c : Symbol(c, Decl(jsxElementTypeLiteralWithGeneric.tsx, 20, 3))

View File

@ -0,0 +1,40 @@
=== tests/cases/compiler/jsxElementTypeLiteralWithGeneric.tsx ===
/// <reference path="react16.d.ts" />
import * as React from "react";
>React : typeof React
declare global {
>global : any
namespace JSX {
type ElementType<P = any> =
>ElementType : ElementType<P>
| {
[K in keyof JSX.IntrinsicElements]: P extends JSX.IntrinsicElements[K]
>JSX : any
>JSX : any
? K
: never;
}[keyof JSX.IntrinsicElements]
>JSX : any
| React.ComponentType<P>;
>React : any
}
}
// should be fine - `ElementType` accepts `div`
let a = <div />;
>a : JSX.Element
><div /> : JSX.Element
>div : any
// Should be an error.
// `ruhroh` is in neither `IntrinsicElements` nor `ElementType`
let c = <ruhroh />;
>c : JSX.Element
><ruhroh /> : JSX.Element
>ruhroh : any

View File

@ -0,0 +1,23 @@
// @strict: true
// @jsx: react
/// <reference path="/.lib/react16.d.ts" />
import * as React from "react";
declare global {
namespace JSX {
type ElementType<P = any> =
| {
[K in keyof JSX.IntrinsicElements]: P extends JSX.IntrinsicElements[K]
? K
: never;
}[keyof JSX.IntrinsicElements]
| React.ComponentType<P>;
}
}
// should be fine - `ElementType` accepts `div`
let a = <div />;
// Should be an error.
// `ruhroh` is in neither `IntrinsicElements` nor `ElementType`
let c = <ruhroh />;