Fixed an issue with JSX children expression not being contextually discriminated (#53502)

This commit is contained in:
Mateusz Burzyński
2023-04-17 12:42:25 -07:00
committed by GitHub
parent 9919f6da1d
commit b269087505
4 changed files with 170 additions and 1 deletions
+1 -1
View File
@@ -29236,7 +29236,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}
function getContextualTypeForChildJsxExpression(node: JsxElement, child: JsxChild, contextFlags: ContextFlags | undefined) {
const attributesType = getApparentTypeOfContextualType(node.openingElement.tagName, contextFlags);
const attributesType = getApparentTypeOfContextualType(node.openingElement.attributes, contextFlags);
// JSX expression is in children of JSX Element, we will look for an "children" attribute (we get the name from JSX.ElementAttributesProperty)
const jsxChildrenPropertyName = getJsxElementChildrenPropertyName(getJsxNamespaceAt(node));
if (!(attributesType && !isTypeAny(attributesType) && jsxChildrenPropertyName && jsxChildrenPropertyName !== "")) {
@@ -0,0 +1,63 @@
=== tests/cases/conformance/jsx/checkJsxChildrenProperty16.tsx ===
/// <reference path="react16.d.ts" />
// repro from #53493
import React = require('react');
>React : Symbol(React, Decl(checkJsxChildrenProperty16.tsx, 0, 0))
export type Props =
>Props : Symbol(Props, Decl(checkJsxChildrenProperty16.tsx, 4, 32))
| { renderNumber?: false; children: (arg: string) => void }
>renderNumber : Symbol(renderNumber, Decl(checkJsxChildrenProperty16.tsx, 7, 5))
>children : Symbol(children, Decl(checkJsxChildrenProperty16.tsx, 7, 27))
>arg : Symbol(arg, Decl(checkJsxChildrenProperty16.tsx, 7, 39))
| {
renderNumber: true;
>renderNumber : Symbol(renderNumber, Decl(checkJsxChildrenProperty16.tsx, 8, 5))
children: (arg: number) => void;
>children : Symbol(children, Decl(checkJsxChildrenProperty16.tsx, 9, 25))
>arg : Symbol(arg, Decl(checkJsxChildrenProperty16.tsx, 10, 17))
};
export declare function Foo(props: Props): JSX.Element;
>Foo : Symbol(Foo, Decl(checkJsxChildrenProperty16.tsx, 11, 6))
>props : Symbol(props, Decl(checkJsxChildrenProperty16.tsx, 13, 28))
>Props : Symbol(Props, Decl(checkJsxChildrenProperty16.tsx, 4, 32))
>JSX : Symbol(JSX, Decl(react16.d.ts, 2493, 12))
>Element : Symbol(JSX.Element, Decl(react16.d.ts, 2494, 23))
export const Test = () => {
>Test : Symbol(Test, Decl(checkJsxChildrenProperty16.tsx, 15, 12))
return (
<>
<Foo>{(value) => {}}</Foo>
>Foo : Symbol(Foo, Decl(checkJsxChildrenProperty16.tsx, 11, 6))
>value : Symbol(value, Decl(checkJsxChildrenProperty16.tsx, 18, 13))
>Foo : Symbol(Foo, Decl(checkJsxChildrenProperty16.tsx, 11, 6))
<Foo renderNumber>{(value) => {}}</Foo>
>Foo : Symbol(Foo, Decl(checkJsxChildrenProperty16.tsx, 11, 6))
>renderNumber : Symbol(renderNumber, Decl(checkJsxChildrenProperty16.tsx, 19, 10))
>value : Symbol(value, Decl(checkJsxChildrenProperty16.tsx, 19, 26))
>Foo : Symbol(Foo, Decl(checkJsxChildrenProperty16.tsx, 11, 6))
<Foo children={(value) => {}} />
>Foo : Symbol(Foo, Decl(checkJsxChildrenProperty16.tsx, 11, 6))
>children : Symbol(children, Decl(checkJsxChildrenProperty16.tsx, 21, 10))
>value : Symbol(value, Decl(checkJsxChildrenProperty16.tsx, 21, 22))
<Foo renderNumber children={(value) => {}} />
>Foo : Symbol(Foo, Decl(checkJsxChildrenProperty16.tsx, 11, 6))
>renderNumber : Symbol(renderNumber, Decl(checkJsxChildrenProperty16.tsx, 22, 10))
>children : Symbol(children, Decl(checkJsxChildrenProperty16.tsx, 22, 23))
>value : Symbol(value, Decl(checkJsxChildrenProperty16.tsx, 22, 35))
</>
);
};
@@ -0,0 +1,76 @@
=== tests/cases/conformance/jsx/checkJsxChildrenProperty16.tsx ===
/// <reference path="react16.d.ts" />
// repro from #53493
import React = require('react');
>React : typeof React
export type Props =
>Props : { renderNumber?: false | undefined; children: (arg: string) => void; } | { renderNumber: true; children: (arg: number) => void; }
| { renderNumber?: false; children: (arg: string) => void }
>renderNumber : false | undefined
>false : false
>children : (arg: string) => void
>arg : string
| {
renderNumber: true;
>renderNumber : true
>true : true
children: (arg: number) => void;
>children : (arg: number) => void
>arg : number
};
export declare function Foo(props: Props): JSX.Element;
>Foo : (props: Props) => JSX.Element
>props : Props
>JSX : any
export const Test = () => {
>Test : () => JSX.Element
>() => { return ( <> <Foo>{(value) => {}}</Foo> <Foo renderNumber>{(value) => {}}</Foo> <Foo children={(value) => {}} /> <Foo renderNumber children={(value) => {}} /> </> );} : () => JSX.Element
return (
>( <> <Foo>{(value) => {}}</Foo> <Foo renderNumber>{(value) => {}}</Foo> <Foo children={(value) => {}} /> <Foo renderNumber children={(value) => {}} /> </> ) : JSX.Element
<>
><> <Foo>{(value) => {}}</Foo> <Foo renderNumber>{(value) => {}}</Foo> <Foo children={(value) => {}} /> <Foo renderNumber children={(value) => {}} /> </> : JSX.Element
<Foo>{(value) => {}}</Foo>
><Foo>{(value) => {}}</Foo> : JSX.Element
>Foo : (props: Props) => JSX.Element
>(value) => {} : (value: string) => void
>value : string
>Foo : (props: Props) => JSX.Element
<Foo renderNumber>{(value) => {}}</Foo>
><Foo renderNumber>{(value) => {}}</Foo> : JSX.Element
>Foo : (props: Props) => JSX.Element
>renderNumber : true
>(value) => {} : (value: number) => void
>value : number
>Foo : (props: Props) => JSX.Element
<Foo children={(value) => {}} />
><Foo children={(value) => {}} /> : JSX.Element
>Foo : (props: Props) => JSX.Element
>children : (value: string) => void
>(value) => {} : (value: string) => void
>value : string
<Foo renderNumber children={(value) => {}} />
><Foo renderNumber children={(value) => {}} /> : JSX.Element
>Foo : (props: Props) => JSX.Element
>renderNumber : true
>children : (value: number) => void
>(value) => {} : (value: number) => void
>value : number
</>
);
};
@@ -0,0 +1,30 @@
// @strict: true
// @noEmit: true
// @jsx: preserve
/// <reference path="/.lib/react16.d.ts" />
// repro from #53493
import React = require('react');
export type Props =
| { renderNumber?: false; children: (arg: string) => void }
| {
renderNumber: true;
children: (arg: number) => void;
};
export declare function Foo(props: Props): JSX.Element;
export const Test = () => {
return (
<>
<Foo>{(value) => {}}</Foo>
<Foo renderNumber>{(value) => {}}</Foo>
<Foo children={(value) => {}} />
<Foo renderNumber children={(value) => {}} />
</>
);
};