Skip to content

Commit 7f3335c

Browse files
committed
Fixed an issue with JSX children expression not being contextually discriminated
1 parent 24373d8 commit 7f3335c

File tree

4 files changed

+170
-1
lines changed

4 files changed

+170
-1
lines changed

src/compiler/checker.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29186,7 +29186,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2918629186
}
2918729187

2918829188
function getContextualTypeForChildJsxExpression(node: JsxElement, child: JsxChild, contextFlags: ContextFlags | undefined) {
29189-
const attributesType = getApparentTypeOfContextualType(node.openingElement.tagName, contextFlags);
29189+
const attributesType = getApparentTypeOfContextualType(node.openingElement.attributes, contextFlags);
2919029190
// JSX expression is in children of JSX Element, we will look for an "children" attribute (we get the name from JSX.ElementAttributesProperty)
2919129191
const jsxChildrenPropertyName = getJsxElementChildrenPropertyName(getJsxNamespaceAt(node));
2919229192
if (!(attributesType && !isTypeAny(attributesType) && jsxChildrenPropertyName && jsxChildrenPropertyName !== "")) {
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
=== tests/cases/conformance/jsx/checkJsxChildrenProperty16.tsx ===
2+
/// <reference path="react16.d.ts" />
3+
4+
// repro from #53493
5+
6+
import React = require('react');
7+
>React : Symbol(React, Decl(checkJsxChildrenProperty16.tsx, 0, 0))
8+
9+
export type Props =
10+
>Props : Symbol(Props, Decl(checkJsxChildrenProperty16.tsx, 4, 32))
11+
12+
| { renderNumber?: false; children: (arg: string) => void }
13+
>renderNumber : Symbol(renderNumber, Decl(checkJsxChildrenProperty16.tsx, 7, 5))
14+
>children : Symbol(children, Decl(checkJsxChildrenProperty16.tsx, 7, 27))
15+
>arg : Symbol(arg, Decl(checkJsxChildrenProperty16.tsx, 7, 39))
16+
17+
| {
18+
renderNumber: true;
19+
>renderNumber : Symbol(renderNumber, Decl(checkJsxChildrenProperty16.tsx, 8, 5))
20+
21+
children: (arg: number) => void;
22+
>children : Symbol(children, Decl(checkJsxChildrenProperty16.tsx, 9, 25))
23+
>arg : Symbol(arg, Decl(checkJsxChildrenProperty16.tsx, 10, 17))
24+
25+
};
26+
27+
export declare function Foo(props: Props): JSX.Element;
28+
>Foo : Symbol(Foo, Decl(checkJsxChildrenProperty16.tsx, 11, 6))
29+
>props : Symbol(props, Decl(checkJsxChildrenProperty16.tsx, 13, 28))
30+
>Props : Symbol(Props, Decl(checkJsxChildrenProperty16.tsx, 4, 32))
31+
>JSX : Symbol(JSX, Decl(react16.d.ts, 2493, 12))
32+
>Element : Symbol(JSX.Element, Decl(react16.d.ts, 2494, 23))
33+
34+
export const Test = () => {
35+
>Test : Symbol(Test, Decl(checkJsxChildrenProperty16.tsx, 15, 12))
36+
37+
return (
38+
<>
39+
<Foo>{(value) => {}}</Foo>
40+
>Foo : Symbol(Foo, Decl(checkJsxChildrenProperty16.tsx, 11, 6))
41+
>value : Symbol(value, Decl(checkJsxChildrenProperty16.tsx, 18, 13))
42+
>Foo : Symbol(Foo, Decl(checkJsxChildrenProperty16.tsx, 11, 6))
43+
44+
<Foo renderNumber>{(value) => {}}</Foo>
45+
>Foo : Symbol(Foo, Decl(checkJsxChildrenProperty16.tsx, 11, 6))
46+
>renderNumber : Symbol(renderNumber, Decl(checkJsxChildrenProperty16.tsx, 19, 10))
47+
>value : Symbol(value, Decl(checkJsxChildrenProperty16.tsx, 19, 26))
48+
>Foo : Symbol(Foo, Decl(checkJsxChildrenProperty16.tsx, 11, 6))
49+
50+
<Foo children={(value) => {}} />
51+
>Foo : Symbol(Foo, Decl(checkJsxChildrenProperty16.tsx, 11, 6))
52+
>children : Symbol(children, Decl(checkJsxChildrenProperty16.tsx, 21, 10))
53+
>value : Symbol(value, Decl(checkJsxChildrenProperty16.tsx, 21, 22))
54+
55+
<Foo renderNumber children={(value) => {}} />
56+
>Foo : Symbol(Foo, Decl(checkJsxChildrenProperty16.tsx, 11, 6))
57+
>renderNumber : Symbol(renderNumber, Decl(checkJsxChildrenProperty16.tsx, 22, 10))
58+
>children : Symbol(children, Decl(checkJsxChildrenProperty16.tsx, 22, 23))
59+
>value : Symbol(value, Decl(checkJsxChildrenProperty16.tsx, 22, 35))
60+
61+
</>
62+
);
63+
};
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
=== tests/cases/conformance/jsx/checkJsxChildrenProperty16.tsx ===
2+
/// <reference path="react16.d.ts" />
3+
4+
// repro from #53493
5+
6+
import React = require('react');
7+
>React : typeof React
8+
9+
export type Props =
10+
>Props : { renderNumber?: false | undefined; children: (arg: string) => void; } | { renderNumber: true; children: (arg: number) => void; }
11+
12+
| { renderNumber?: false; children: (arg: string) => void }
13+
>renderNumber : false | undefined
14+
>false : false
15+
>children : (arg: string) => void
16+
>arg : string
17+
18+
| {
19+
renderNumber: true;
20+
>renderNumber : true
21+
>true : true
22+
23+
children: (arg: number) => void;
24+
>children : (arg: number) => void
25+
>arg : number
26+
27+
};
28+
29+
export declare function Foo(props: Props): JSX.Element;
30+
>Foo : (props: Props) => JSX.Element
31+
>props : Props
32+
>JSX : any
33+
34+
export const Test = () => {
35+
>Test : () => JSX.Element
36+
>() => { return ( <> <Foo>{(value) => {}}</Foo> <Foo renderNumber>{(value) => {}}</Foo> <Foo children={(value) => {}} /> <Foo renderNumber children={(value) => {}} /> </> );} : () => JSX.Element
37+
38+
return (
39+
>( <> <Foo>{(value) => {}}</Foo> <Foo renderNumber>{(value) => {}}</Foo> <Foo children={(value) => {}} /> <Foo renderNumber children={(value) => {}} /> </> ) : JSX.Element
40+
41+
<>
42+
><> <Foo>{(value) => {}}</Foo> <Foo renderNumber>{(value) => {}}</Foo> <Foo children={(value) => {}} /> <Foo renderNumber children={(value) => {}} /> </> : JSX.Element
43+
44+
<Foo>{(value) => {}}</Foo>
45+
><Foo>{(value) => {}}</Foo> : JSX.Element
46+
>Foo : (props: Props) => JSX.Element
47+
>(value) => {} : (value: string) => void
48+
>value : string
49+
>Foo : (props: Props) => JSX.Element
50+
51+
<Foo renderNumber>{(value) => {}}</Foo>
52+
><Foo renderNumber>{(value) => {}}</Foo> : JSX.Element
53+
>Foo : (props: Props) => JSX.Element
54+
>renderNumber : true
55+
>(value) => {} : (value: number) => void
56+
>value : number
57+
>Foo : (props: Props) => JSX.Element
58+
59+
<Foo children={(value) => {}} />
60+
><Foo children={(value) => {}} /> : JSX.Element
61+
>Foo : (props: Props) => JSX.Element
62+
>children : (value: string) => void
63+
>(value) => {} : (value: string) => void
64+
>value : string
65+
66+
<Foo renderNumber children={(value) => {}} />
67+
><Foo renderNumber children={(value) => {}} /> : JSX.Element
68+
>Foo : (props: Props) => JSX.Element
69+
>renderNumber : true
70+
>children : (value: number) => void
71+
>(value) => {} : (value: number) => void
72+
>value : number
73+
74+
</>
75+
);
76+
};
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// @strict: true
2+
// @noEmit: true
3+
// @jsx: preserve
4+
5+
/// <reference path="/.lib/react16.d.ts" />
6+
7+
// repro from #53493
8+
9+
import React = require('react');
10+
11+
export type Props =
12+
| { renderNumber?: false; children: (arg: string) => void }
13+
| {
14+
renderNumber: true;
15+
children: (arg: number) => void;
16+
};
17+
18+
export declare function Foo(props: Props): JSX.Element;
19+
20+
export const Test = () => {
21+
return (
22+
<>
23+
<Foo>{(value) => {}}</Foo>
24+
<Foo renderNumber>{(value) => {}}</Foo>
25+
26+
<Foo children={(value) => {}} />
27+
<Foo renderNumber children={(value) => {}} />
28+
</>
29+
);
30+
};

0 commit comments

Comments
 (0)