Fix contextual types for a single jsx child (#31040)

This commit is contained in:
Wesley Wigham 2019-04-23 13:51:39 -07:00 committed by GitHub
parent 54fa950757
commit b47194bfa1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 212 additions and 8 deletions

View File

@ -11773,6 +11773,10 @@ namespace ts {
}
}
function getSemanticJsxChildren(children: NodeArray<JsxChild>) {
return filter(children, i => !isJsxText(i) || !i.containsOnlyTriviaWhiteSpaces);
}
function elaborateJsxComponents(node: JsxAttributes, source: Type, target: Type, relation: Map<RelationComparisonResult>) {
let result = elaborateElementwise(generateJsxAttributes(node), source, target, relation);
let invalidTextDiagnostic: DiagnosticMessage | undefined;
@ -11782,7 +11786,7 @@ namespace ts {
const childrenPropName = childPropName === undefined ? "children" : unescapeLeadingUnderscores(childPropName);
const childrenNameType = getLiteralType(childrenPropName);
const childrenTargetType = getIndexedAccessType(target, childrenNameType);
const validChildren = filter(containingElement.children, i => !isJsxText(i) || !i.containsOnlyTriviaWhiteSpaces);
const validChildren = getSemanticJsxChildren(containingElement.children);
if (!length(validChildren)) {
return result;
}
@ -18193,16 +18197,17 @@ namespace ts {
if (!(attributesType && !isTypeAny(attributesType) && jsxChildrenPropertyName && jsxChildrenPropertyName !== "")) {
return undefined;
}
const childIndex = node.children.indexOf(child);
const realChildren = getSemanticJsxChildren(node.children);
const childIndex = realChildren.indexOf(child);
const childFieldType = getTypeOfPropertyOfContextualType(attributesType, jsxChildrenPropertyName);
return childFieldType && mapType(childFieldType, t => {
return childFieldType && (realChildren.length === 1 ? childFieldType : mapType(childFieldType, t => {
if (isArrayLikeType(t)) {
return getIndexedAccessType(t, getLiteralType(childIndex));
}
else {
return t;
}
}, /*noReductions*/ true);
}, /*noReductions*/ true));
}
function getContextualTypeForJsxExpression(node: JsxExpression): Type | undefined {

View File

@ -2,6 +2,7 @@ tests/cases/compiler/index.tsx(14,9): error TS2322: Type 'number' is not assigna
tests/cases/compiler/index.tsx(18,15): error TS2747: 'Blah' components don't accept text as child elements. Text in JSX has the type 'string', but the expected type of 'children' is '(x: number) => string'.
tests/cases/compiler/index.tsx(23,10): error TS2746: This JSX tag's 'children' prop expects a single child of type '(x: number) => string', but multiple children were provided.
tests/cases/compiler/index.tsx(37,10): error TS2745: This JSX tag's 'children' prop expects type '((x: number) => string)[]' which requires multiple children, but only a single child was provided.
tests/cases/compiler/index.tsx(38,4): error TS7006: Parameter 'x' implicitly has an 'any' type.
tests/cases/compiler/index.tsx(42,10): error TS2745: This JSX tag's 'children' prop expects type '((x: number) => string)[]' which requires multiple children, but only a single child was provided.
tests/cases/compiler/index.tsx(48,9): error TS2322: Type 'number' is not assignable to type 'string'.
tests/cases/compiler/index.tsx(49,9): error TS2322: Type 'number' is not assignable to type 'string'.
@ -13,7 +14,7 @@ tests/cases/compiler/index.tsx(73,9): error TS2322: Type 'number' is not assigna
tests/cases/compiler/index.tsx(74,9): error TS2322: Type 'number' is not assignable to type 'string'.
==== tests/cases/compiler/index.tsx (11 errors) ====
==== tests/cases/compiler/index.tsx (12 errors) ====
/// <reference path="/.lib/react16.d.ts" />
import * as React from "react";
@ -64,6 +65,8 @@ tests/cases/compiler/index.tsx(74,9): error TS2322: Type 'number' is not assigna
~~~~~
!!! error TS2745: This JSX tag's 'children' prop expects type '((x: number) => string)[]' which requires multiple children, but only a single child was provided.
{x => x}
~
!!! error TS7006: Parameter 'x' implicitly has an 'any' type.
</Blah2>
// Blah2 components don't accept text as child elements

View File

@ -85,9 +85,9 @@ var a = <Blah2>
>Blah2 : (props: PropsArr) => JSX.Element
{x => x}
>x => x : (x: number) => number
>x : number
>x : number
>x => x : (x: any) => any
>x : any
>x : any
</Blah2>
>Blah2 : (props: PropsArr) => JSX.Element

View File

@ -0,0 +1,61 @@
//// [jsxChildrenSingleChildConfusableWithMultipleChildrenNoError.tsx]
/// <reference path="/.lib/react16.d.ts" />
import * as React from 'react'
type Tab = [string, React.ReactNode] // [tabName, tabContent]
interface Props {
children: Tab[]
}
function TabLayout(props: Props) {
return <div/>
}
export class App extends React.Component<{}> {
render() {
return <TabLayout>
{[
['Users', <div/>],
['Products', <div/>]
]}
</TabLayout>
}
}
//// [jsxChildrenSingleChildConfusableWithMultipleChildrenNoError.js]
"use strict";
/// <reference path="react16.d.ts" />
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 (b.hasOwnProperty(p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
exports.__esModule = true;
var React = require("react");
function TabLayout(props) {
return React.createElement("div", null);
}
var App = /** @class */ (function (_super) {
__extends(App, _super);
function App() {
return _super !== null && _super.apply(this, arguments) || this;
}
App.prototype.render = function () {
return React.createElement(TabLayout, null, [
['Users', React.createElement("div", null)],
['Products', React.createElement("div", null)]
]);
};
return App;
}(React.Component));
exports.App = App;

View File

@ -0,0 +1,52 @@
=== tests/cases/compiler/jsxChildrenSingleChildConfusableWithMultipleChildrenNoError.tsx ===
/// <reference path="react16.d.ts" />
import * as React from 'react'
>React : Symbol(React, Decl(jsxChildrenSingleChildConfusableWithMultipleChildrenNoError.tsx, 2, 6))
type Tab = [string, React.ReactNode] // [tabName, tabContent]
>Tab : Symbol(Tab, Decl(jsxChildrenSingleChildConfusableWithMultipleChildrenNoError.tsx, 2, 30))
>React : Symbol(React, Decl(jsxChildrenSingleChildConfusableWithMultipleChildrenNoError.tsx, 2, 6))
>ReactNode : Symbol(React.ReactNode, Decl(react16.d.ts, 216, 49))
interface Props {
>Props : Symbol(Props, Decl(jsxChildrenSingleChildConfusableWithMultipleChildrenNoError.tsx, 4, 36))
children: Tab[]
>children : Symbol(Props.children, Decl(jsxChildrenSingleChildConfusableWithMultipleChildrenNoError.tsx, 6, 17))
>Tab : Symbol(Tab, Decl(jsxChildrenSingleChildConfusableWithMultipleChildrenNoError.tsx, 2, 30))
}
function TabLayout(props: Props) {
>TabLayout : Symbol(TabLayout, Decl(jsxChildrenSingleChildConfusableWithMultipleChildrenNoError.tsx, 8, 1))
>props : Symbol(props, Decl(jsxChildrenSingleChildConfusableWithMultipleChildrenNoError.tsx, 10, 19))
>Props : Symbol(Props, Decl(jsxChildrenSingleChildConfusableWithMultipleChildrenNoError.tsx, 4, 36))
return <div/>
>div : Symbol(JSX.IntrinsicElements.div, Decl(react16.d.ts, 2420, 114))
}
export class App extends React.Component<{}> {
>App : Symbol(App, Decl(jsxChildrenSingleChildConfusableWithMultipleChildrenNoError.tsx, 12, 1))
>React.Component : Symbol(React.Component, Decl(react16.d.ts, 345, 54), Decl(react16.d.ts, 349, 94))
>React : Symbol(React, Decl(jsxChildrenSingleChildConfusableWithMultipleChildrenNoError.tsx, 2, 6))
>Component : Symbol(React.Component, Decl(react16.d.ts, 345, 54), Decl(react16.d.ts, 349, 94))
render() {
>render : Symbol(App.render, Decl(jsxChildrenSingleChildConfusableWithMultipleChildrenNoError.tsx, 14, 46))
return <TabLayout>
>TabLayout : Symbol(TabLayout, Decl(jsxChildrenSingleChildConfusableWithMultipleChildrenNoError.tsx, 8, 1))
{[
['Users', <div/>],
>div : Symbol(JSX.IntrinsicElements.div, Decl(react16.d.ts, 2420, 114))
['Products', <div/>]
>div : Symbol(JSX.IntrinsicElements.div, Decl(react16.d.ts, 2420, 114))
]}
</TabLayout>
>TabLayout : Symbol(TabLayout, Decl(jsxChildrenSingleChildConfusableWithMultipleChildrenNoError.tsx, 8, 1))
}
}

View File

@ -0,0 +1,57 @@
=== tests/cases/compiler/jsxChildrenSingleChildConfusableWithMultipleChildrenNoError.tsx ===
/// <reference path="react16.d.ts" />
import * as React from 'react'
>React : typeof React
type Tab = [string, React.ReactNode] // [tabName, tabContent]
>Tab : [string, React.ReactNode]
>React : any
interface Props {
children: Tab[]
>children : [string, React.ReactNode][]
}
function TabLayout(props: Props) {
>TabLayout : (props: Props) => JSX.Element
>props : Props
return <div/>
><div/> : JSX.Element
>div : any
}
export class App extends React.Component<{}> {
>App : App
>React.Component : React.Component<{}, {}, any>
>React : typeof React
>Component : typeof React.Component
render() {
>render : () => JSX.Element
return <TabLayout>
><TabLayout> {[ ['Users', <div/>], ['Products', <div/>] ]} </TabLayout> : JSX.Element
>TabLayout : (props: Props) => JSX.Element
{[
>[ ['Users', <div/>], ['Products', <div/>] ] : [string, JSX.Element][]
['Users', <div/>],
>['Users', <div/>] : [string, JSX.Element]
>'Users' : "Users"
><div/> : JSX.Element
>div : any
['Products', <div/>]
>['Products', <div/>] : [string, JSX.Element]
>'Products' : "Products"
><div/> : JSX.Element
>div : any
]}
</TabLayout>
>TabLayout : (props: Props) => JSX.Element
}
}

View File

@ -0,0 +1,26 @@
// @skipLibCheck: true
// @jsx: react
/// <reference path="/.lib/react16.d.ts" />
import * as React from 'react'
type Tab = [string, React.ReactNode] // [tabName, tabContent]
interface Props {
children: Tab[]
}
function TabLayout(props: Props) {
return <div/>
}
export class App extends React.Component<{}> {
render() {
return <TabLayout>
{[
['Users', <div/>],
['Products', <div/>]
]}
</TabLayout>
}
}