diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 82521698fa9..3fdee5e9a10 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -13121,12 +13121,12 @@ namespace ts { if (isJsxAttribute(node.parent)) { // JSX expression is in JSX attribute - return getTypeOfPropertyOfType(attributesType, node.parent.name.escapedText); + return getTypeOfPropertyOfContextualType(attributesType, node.parent.name.escapedText); } else if (node.parent.kind === SyntaxKind.JsxElement) { // JSX expression is in children of JSX Element, we will look for an "children" atttribute (we get the name from JSX.ElementAttributesProperty) const jsxChildrenPropertyName = getJsxElementChildrenPropertyname(); - return jsxChildrenPropertyName && jsxChildrenPropertyName !== "" ? getTypeOfPropertyOfType(attributesType, jsxChildrenPropertyName) : anyType; + return jsxChildrenPropertyName && jsxChildrenPropertyName !== "" ? getTypeOfPropertyOfContextualType(attributesType, jsxChildrenPropertyName) : anyType; } else { // JSX expression is in JSX spread attribute @@ -13144,7 +13144,7 @@ namespace ts { if (!attributesType || isTypeAny(attributesType)) { return undefined; } - return getTypeOfPropertyOfType(attributesType, attribute.name.escapedText); + return getTypeOfPropertyOfContextualType(attributesType, attribute.name.escapedText); } else { return attributesType; diff --git a/tests/baselines/reference/tsxInferenceShouldNotYieldAnyOnUnions.js b/tests/baselines/reference/tsxInferenceShouldNotYieldAnyOnUnions.js new file mode 100644 index 00000000000..0459b56d874 --- /dev/null +++ b/tests/baselines/reference/tsxInferenceShouldNotYieldAnyOnUnions.js @@ -0,0 +1,40 @@ +//// [index.tsx] +namespace JSX { + export interface Element {} +} + +type Props = PropsBase | PropsWithConvert; + +interface PropsBase { + data: T; +} + +interface PropsWithConvert extends PropsBase { + convert: (t: T) => string; +} + +function ShouldInferFromData(props: Props): JSX.Element { + return
; +} + +// Sanity check: function call equivalent versions work fine +ShouldInferFromData({ data: "1" }); +ShouldInferFromData({ data: "1", convert: n => "" + n }); +ShouldInferFromData({ data: 2, convert: n => "" + n }); + + +const f1 = ; +const f2 = "" + n} />; +const f3 = "" + n} />; + +//// [index.jsx] +function ShouldInferFromData(props) { + return
; +} +// Sanity check: function call equivalent versions work fine +ShouldInferFromData({ data: "1" }); +ShouldInferFromData({ data: "1", convert: function (n) { return "" + n; } }); +ShouldInferFromData({ data: 2, convert: function (n) { return "" + n; } }); +var f1 = ; +var f2 = ; +var f3 = ; diff --git a/tests/baselines/reference/tsxInferenceShouldNotYieldAnyOnUnions.symbols b/tests/baselines/reference/tsxInferenceShouldNotYieldAnyOnUnions.symbols new file mode 100644 index 00000000000..b6163a36df6 --- /dev/null +++ b/tests/baselines/reference/tsxInferenceShouldNotYieldAnyOnUnions.symbols @@ -0,0 +1,90 @@ +=== tests/cases/compiler/index.tsx === +namespace JSX { +>JSX : Symbol(JSX, Decl(index.tsx, 0, 0)) + + export interface Element {} +>Element : Symbol(Element, Decl(index.tsx, 0, 15)) +} + +type Props = PropsBase | PropsWithConvert; +>Props : Symbol(Props, Decl(index.tsx, 2, 1)) +>T : Symbol(T, Decl(index.tsx, 4, 11)) +>PropsBase : Symbol(PropsBase, Decl(index.tsx, 4, 56)) +>PropsWithConvert : Symbol(PropsWithConvert, Decl(index.tsx, 8, 1)) +>T : Symbol(T, Decl(index.tsx, 4, 11)) + +interface PropsBase { +>PropsBase : Symbol(PropsBase, Decl(index.tsx, 4, 56)) +>T : Symbol(T, Decl(index.tsx, 6, 20)) + + data: T; +>data : Symbol(PropsBase.data, Decl(index.tsx, 6, 24)) +>T : Symbol(T, Decl(index.tsx, 6, 20)) +} + +interface PropsWithConvert extends PropsBase { +>PropsWithConvert : Symbol(PropsWithConvert, Decl(index.tsx, 8, 1)) +>T : Symbol(T, Decl(index.tsx, 10, 27)) +>PropsBase : Symbol(PropsBase, Decl(index.tsx, 4, 56)) +>T : Symbol(T, Decl(index.tsx, 10, 27)) + + convert: (t: T) => string; +>convert : Symbol(PropsWithConvert.convert, Decl(index.tsx, 10, 52)) +>t : Symbol(t, Decl(index.tsx, 11, 14)) +>T : Symbol(T, Decl(index.tsx, 10, 27)) +} + +function ShouldInferFromData(props: Props): JSX.Element { +>ShouldInferFromData : Symbol(ShouldInferFromData, Decl(index.tsx, 12, 1)) +>T : Symbol(T, Decl(index.tsx, 14, 29)) +>props : Symbol(props, Decl(index.tsx, 14, 32)) +>Props : Symbol(Props, Decl(index.tsx, 2, 1)) +>T : Symbol(T, Decl(index.tsx, 14, 29)) +>JSX : Symbol(JSX, Decl(index.tsx, 0, 0)) +>Element : Symbol(JSX.Element, Decl(index.tsx, 0, 15)) + + return
; +>div : Symbol(unknown) +} + +// Sanity check: function call equivalent versions work fine +ShouldInferFromData({ data: "1" }); +>ShouldInferFromData : Symbol(ShouldInferFromData, Decl(index.tsx, 12, 1)) +>data : Symbol(data, Decl(index.tsx, 19, 21)) + +ShouldInferFromData({ data: "1", convert: n => "" + n }); +>ShouldInferFromData : Symbol(ShouldInferFromData, Decl(index.tsx, 12, 1)) +>data : Symbol(data, Decl(index.tsx, 20, 21)) +>convert : Symbol(convert, Decl(index.tsx, 20, 32)) +>n : Symbol(n, Decl(index.tsx, 20, 41)) +>n : Symbol(n, Decl(index.tsx, 20, 41)) + +ShouldInferFromData({ data: 2, convert: n => "" + n }); +>ShouldInferFromData : Symbol(ShouldInferFromData, Decl(index.tsx, 12, 1)) +>data : Symbol(data, Decl(index.tsx, 21, 21)) +>convert : Symbol(convert, Decl(index.tsx, 21, 30)) +>n : Symbol(n, Decl(index.tsx, 21, 39)) +>n : Symbol(n, Decl(index.tsx, 21, 39)) + + +const f1 = ; +>f1 : Symbol(f1, Decl(index.tsx, 24, 5)) +>ShouldInferFromData : Symbol(ShouldInferFromData, Decl(index.tsx, 12, 1)) +>data : Symbol(data, Decl(index.tsx, 24, 31)) + +const f2 = "" + n} />; +>f2 : Symbol(f2, Decl(index.tsx, 25, 5)) +>ShouldInferFromData : Symbol(ShouldInferFromData, Decl(index.tsx, 12, 1)) +>data : Symbol(data, Decl(index.tsx, 25, 31)) +>convert : Symbol(convert, Decl(index.tsx, 25, 42)) +>n : Symbol(n, Decl(index.tsx, 25, 52)) +>n : Symbol(n, Decl(index.tsx, 25, 52)) + +const f3 = "" + n} />; +>f3 : Symbol(f3, Decl(index.tsx, 26, 5)) +>ShouldInferFromData : Symbol(ShouldInferFromData, Decl(index.tsx, 12, 1)) +>data : Symbol(data, Decl(index.tsx, 26, 31)) +>convert : Symbol(convert, Decl(index.tsx, 26, 40)) +>n : Symbol(n, Decl(index.tsx, 26, 50)) +>n : Symbol(n, Decl(index.tsx, 26, 50)) + diff --git a/tests/baselines/reference/tsxInferenceShouldNotYieldAnyOnUnions.types b/tests/baselines/reference/tsxInferenceShouldNotYieldAnyOnUnions.types new file mode 100644 index 00000000000..68ad55854a7 --- /dev/null +++ b/tests/baselines/reference/tsxInferenceShouldNotYieldAnyOnUnions.types @@ -0,0 +1,118 @@ +=== tests/cases/compiler/index.tsx === +namespace JSX { +>JSX : any + + export interface Element {} +>Element : Element +} + +type Props = PropsBase | PropsWithConvert; +>Props : Props +>T : T +>PropsBase : PropsBase +>PropsWithConvert : PropsWithConvert +>T : T + +interface PropsBase { +>PropsBase : PropsBase +>T : T + + data: T; +>data : T +>T : T +} + +interface PropsWithConvert extends PropsBase { +>PropsWithConvert : PropsWithConvert +>T : T +>PropsBase : PropsBase +>T : T + + convert: (t: T) => string; +>convert : (t: T) => string +>t : T +>T : T +} + +function ShouldInferFromData(props: Props): JSX.Element { +>ShouldInferFromData : (props: Props) => JSX.Element +>T : T +>props : Props +>Props : Props +>T : T +>JSX : any +>Element : JSX.Element + + return
; +>
: JSX.Element +>div : any +} + +// Sanity check: function call equivalent versions work fine +ShouldInferFromData({ data: "1" }); +>ShouldInferFromData({ data: "1" }) : JSX.Element +>ShouldInferFromData : (props: Props) => JSX.Element +>{ data: "1" } : { data: string; } +>data : string +>"1" : "1" + +ShouldInferFromData({ data: "1", convert: n => "" + n }); +>ShouldInferFromData({ data: "1", convert: n => "" + n }) : JSX.Element +>ShouldInferFromData : (props: Props) => JSX.Element +>{ data: "1", convert: n => "" + n } : { data: string; convert: (n: string) => string; } +>data : string +>"1" : "1" +>convert : (n: string) => string +>n => "" + n : (n: string) => string +>n : string +>"" + n : string +>"" : "" +>n : string + +ShouldInferFromData({ data: 2, convert: n => "" + n }); +>ShouldInferFromData({ data: 2, convert: n => "" + n }) : JSX.Element +>ShouldInferFromData : (props: Props) => JSX.Element +>{ data: 2, convert: n => "" + n } : { data: number; convert: (n: number) => string; } +>data : number +>2 : 2 +>convert : (n: number) => string +>n => "" + n : (n: number) => string +>n : number +>"" + n : string +>"" : "" +>n : number + + +const f1 = ; +>f1 : JSX.Element +> : JSX.Element +>ShouldInferFromData : (props: Props) => JSX.Element +>data : string +>"1" : "1" + +const f2 = "" + n} />; +>f2 : JSX.Element +> "" + n} /> : JSX.Element +>ShouldInferFromData : (props: Props) => JSX.Element +>data : string +>"1" : "1" +>convert : (n: "1") => string +>n => "" + n : (n: "1") => string +>n : "1" +>"" + n : string +>"" : "" +>n : "1" + +const f3 = "" + n} />; +>f3 : JSX.Element +> "" + n} /> : JSX.Element +>ShouldInferFromData : (props: Props) => JSX.Element +>data : number +>2 : 2 +>convert : (n: 2) => string +>n => "" + n : (n: 2) => string +>n : 2 +>"" + n : string +>"" : "" +>n : 2 + diff --git a/tests/cases/compiler/tsxInferenceShouldNotYieldAnyOnUnions.tsx b/tests/cases/compiler/tsxInferenceShouldNotYieldAnyOnUnions.tsx new file mode 100644 index 00000000000..a0d4f5984e4 --- /dev/null +++ b/tests/cases/compiler/tsxInferenceShouldNotYieldAnyOnUnions.tsx @@ -0,0 +1,29 @@ +// @jsx: preserve +// @filename: index.tsx +namespace JSX { + export interface Element {} +} + +type Props = PropsBase | PropsWithConvert; + +interface PropsBase { + data: T; +} + +interface PropsWithConvert extends PropsBase { + convert: (t: T) => string; +} + +function ShouldInferFromData(props: Props): JSX.Element { + return
; +} + +// Sanity check: function call equivalent versions work fine +ShouldInferFromData({ data: "1" }); +ShouldInferFromData({ data: "1", convert: n => "" + n }); +ShouldInferFromData({ data: 2, convert: n => "" + n }); + + +const f1 = ; +const f2 = "" + n} />; +const f3 = "" + n} />; \ No newline at end of file