Strongly typecheck unions of intrinsic tag names (#28557)

This commit is contained in:
Wesley Wigham
2018-11-15 13:46:32 -08:00
committed by GitHub
parent 1ad7b0fe69
commit b90d2910fb
6 changed files with 96 additions and 22 deletions
+22 -20
View File
@@ -18355,16 +18355,31 @@ namespace ts {
return getNameFromJsxElementAttributesContainer(JsxNames.ElementChildrenAttributeNameContainer, jsxNamespace);
}
function getUninstantiatedJsxSignaturesOfType(elementType: Type): ReadonlyArray<Signature> {
function getUninstantiatedJsxSignaturesOfType(elementType: Type, caller: JsxOpeningLikeElement): ReadonlyArray<Signature> {
if (elementType.flags & TypeFlags.String) {
return [anySignature];
}
else if (elementType.flags & TypeFlags.StringLiteral) {
const intrinsicType = getIntrinsicAttributesTypeFromStringLiteralType(elementType as StringLiteralType, caller);
if (!intrinsicType) {
error(caller, Diagnostics.Property_0_does_not_exist_on_type_1, (elementType as StringLiteralType).value, "JSX." + JsxNames.IntrinsicElements);
return emptyArray;
}
else {
const fakeSignature = createSignatureForJSXIntrinsic(caller, intrinsicType);
return [fakeSignature];
}
}
const apparentElemType = getApparentType(elementType);
// Resolve the signatures, preferring constructor
let signatures = getSignaturesOfType(elementType, SignatureKind.Construct);
let signatures = getSignaturesOfType(apparentElemType, SignatureKind.Construct);
if (signatures.length === 0) {
// No construct signatures, try call signatures
signatures = getSignaturesOfType(elementType, SignatureKind.Call);
signatures = getSignaturesOfType(apparentElemType, SignatureKind.Call);
}
if (signatures.length === 0 && elementType.flags & TypeFlags.Union) {
if (signatures.length === 0 && apparentElemType.flags & TypeFlags.Union) {
// If each member has some combination of new/call signatures; make a union signature list for those
signatures = getUnionSignatures(map((elementType as UnionType).types, getUninstantiatedJsxSignaturesOfType));
signatures = getUnionSignatures(map((apparentElemType as UnionType).types, t => getUninstantiatedJsxSignaturesOfType(t, caller)));
}
return signatures;
}
@@ -20547,21 +20562,8 @@ namespace ts {
return resolveErrorCall(node);
}
if (exprTypes.flags & TypeFlags.StringLiteral) {
const intrinsicType = getIntrinsicAttributesTypeFromStringLiteralType(exprTypes as StringLiteralType, node);
if (!intrinsicType) {
error(node, Diagnostics.Property_0_does_not_exist_on_type_1, (exprTypes as StringLiteralType).value, "JSX." + JsxNames.IntrinsicElements);
return resolveUntypedCall(node);
}
else {
const fakeSignature = createSignatureForJSXIntrinsic(node, intrinsicType);
checkTypeAssignableToAndOptionallyElaborate(checkExpressionWithContextualType(node.attributes, getEffectiveFirstArgumentForJsxSignature(fakeSignature, node), /*mapper*/ undefined), intrinsicType, node.tagName, node.attributes);
return fakeSignature;
}
}
const signatures = getUninstantiatedJsxSignaturesOfType(apparentType);
if (exprTypes.flags & TypeFlags.String || isUntypedFunctionCall(exprTypes, apparentType, signatures.length, /*constructSignatures*/ 0)) {
const signatures = getUninstantiatedJsxSignaturesOfType(exprTypes, node);
if (isUntypedFunctionCall(exprTypes, apparentType, signatures.length, /*constructSignatures*/ 0)) {
return resolveUntypedCall(node);
}
@@ -0,0 +1,17 @@
//// [jsxIntrinsicUnions.tsx]
/// <reference path="/.lib/react16.d.ts" />
import * as React from "react";
const El = Math.random() ? 'h1' : 'h2';
const tag = <El className="ok" key="key">{"Title"}</El>;
//// [jsxIntrinsicUnions.js]
"use strict";
/// <reference path="react16.d.ts" />
exports.__esModule = true;
var React = require("react");
var El = Math.random() ? 'h1' : 'h2';
var tag = React.createElement(El, { className: "ok", key: "key" }, "Title");
@@ -0,0 +1,19 @@
=== tests/cases/compiler/jsxIntrinsicUnions.tsx ===
/// <reference path="react16.d.ts" />
import * as React from "react";
>React : Symbol(React, Decl(jsxIntrinsicUnions.tsx, 2, 6))
const El = Math.random() ? 'h1' : 'h2';
>El : Symbol(El, Decl(jsxIntrinsicUnions.tsx, 4, 5))
>Math.random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --))
>Math : Symbol(Math, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --))
const tag = <El className="ok" key="key">{"Title"}</El>;
>tag : Symbol(tag, Decl(jsxIntrinsicUnions.tsx, 6, 5))
>El : Symbol(El, Decl(jsxIntrinsicUnions.tsx, 4, 5))
>className : Symbol(className, Decl(jsxIntrinsicUnions.tsx, 6, 15))
>key : Symbol(key, Decl(jsxIntrinsicUnions.tsx, 6, 30))
>El : Symbol(El, Decl(jsxIntrinsicUnions.tsx, 4, 5))
@@ -0,0 +1,25 @@
=== tests/cases/compiler/jsxIntrinsicUnions.tsx ===
/// <reference path="react16.d.ts" />
import * as React from "react";
>React : typeof React
const El = Math.random() ? 'h1' : 'h2';
>El : "h1" | "h2"
>Math.random() ? 'h1' : 'h2' : "h1" | "h2"
>Math.random() : number
>Math.random : () => number
>Math : Math
>random : () => number
>'h1' : "h1"
>'h2' : "h2"
const tag = <El className="ok" key="key">{"Title"}</El>;
>tag : JSX.Element
><El className="ok" key="key">{"Title"}</El> : JSX.Element
>El : "h1" | "h2"
>className : string
>key : string
>"Title" : "Title"
>El : "h1" | "h2"
@@ -1,7 +1,8 @@
tests/cases/conformance/jsx/tsxDynamicTagName3.tsx(9,1): error TS2339: Property 'h1' does not exist on type 'JSX.IntrinsicElements'.
tests/cases/conformance/jsx/tsxDynamicTagName3.tsx(9,2): error TS2604: JSX element type 'CustomTag' does not have any construct or call signatures.
==== tests/cases/conformance/jsx/tsxDynamicTagName3.tsx (1 errors) ====
==== tests/cases/conformance/jsx/tsxDynamicTagName3.tsx (2 errors) ====
declare module JSX {
interface Element { }
interface IntrinsicElements {
@@ -12,4 +13,6 @@ tests/cases/conformance/jsx/tsxDynamicTagName3.tsx(9,1): error TS2339: Property
var CustomTag: "h1" = "h1";
<CustomTag> Hello World </CustomTag> // This should be an error. we will try look up string literal type in JSX.IntrinsicElements
~~~~~~~~~~~
!!! error TS2339: Property 'h1' does not exist on type 'JSX.IntrinsicElements'.
!!! error TS2339: Property 'h1' does not exist on type 'JSX.IntrinsicElements'.
~~~~~~~~~
!!! error TS2604: JSX element type 'CustomTag' does not have any construct or call signatures.
@@ -0,0 +1,8 @@
// @jsx: react
/// <reference path="/.lib/react16.d.ts" />
import * as React from "react";
const El = Math.random() ? 'h1' : 'h2';
const tag = <El className="ok" key="key">{"Title"}</El>;