mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-15 03:23:08 -06:00
Fix contextual types for a single jsx child (#31040)
This commit is contained in:
parent
54fa950757
commit
b47194bfa1
@ -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 {
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
@ -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))
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
@ -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>
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user