diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 91ff98be94646..5a169c820c7ef 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -30160,7 +30160,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { */ function createJsxAttributesTypeFromAttributesProperty(openingLikeElement: JsxOpeningLikeElement, checkMode: CheckMode | undefined) { const attributes = openingLikeElement.attributes; - const attributesType = getContextualType(attributes, ContextFlags.None); + const contextualType = getContextualType(attributes, ContextFlags.None); const allAttributesTable = strictNullChecks ? createSymbolTable() : undefined; let attributesTable = createSymbolTable(); let spread: Type = emptyJsxObjectType; @@ -30189,12 +30189,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (attributeDecl.name.escapedText === jsxChildrenPropertyName) { explicitlySpecifyChildrenAttribute = true; } - if (attributesType) { - const prop = getPropertyOfType(attributesType, member.escapedName); + if (contextualType) { + const prop = getPropertyOfType(contextualType, member.escapedName); if (prop && prop.declarations && isDeprecatedSymbol(prop)) { addDeprecatedSuggestion(attributeDecl.name, prop.declarations, attributeDecl.name.escapedText as string); } } + if (contextualType && checkMode && checkMode & CheckMode.Inferential && !(checkMode & CheckMode.SkipContextSensitive) && isContextSensitive(attributeDecl)) { + const inferenceContext = getInferenceContext(attributes); + Debug.assert(inferenceContext); // In CheckMode.Inferential we should always have an inference context + const inferenceNode = (attributeDecl.initializer as JsxExpression).expression!; + addIntraExpressionInferenceSite(inferenceContext, inferenceNode, exprType); + } } else { Debug.assert(attributeDecl.kind === SyntaxKind.JsxSpreadAttribute); diff --git a/tests/baselines/reference/intraExpressionInferencesJsx.symbols b/tests/baselines/reference/intraExpressionInferencesJsx.symbols new file mode 100644 index 0000000000000..798c76fbcefb5 --- /dev/null +++ b/tests/baselines/reference/intraExpressionInferencesJsx.symbols @@ -0,0 +1,274 @@ +=== tests/cases/conformance/types/typeRelationships/typeInference/intraExpressionInferencesJsx.tsx === +/// + +// repro from #52798 + +type A = { +>A : Symbol(A, Decl(intraExpressionInferencesJsx.tsx, 0, 0)) + + a: boolean; +>a : Symbol(a, Decl(intraExpressionInferencesJsx.tsx, 4, 10)) + +}; + +type B = { +>B : Symbol(B, Decl(intraExpressionInferencesJsx.tsx, 6, 2)) + + b: string; +>b : Symbol(b, Decl(intraExpressionInferencesJsx.tsx, 8, 10)) + +}; + +type C = { +>C : Symbol(C, Decl(intraExpressionInferencesJsx.tsx, 10, 2)) + + c: number; +>c : Symbol(c, Decl(intraExpressionInferencesJsx.tsx, 12, 10)) + +}; + +type Animations = { +>Animations : Symbol(Animations, Decl(intraExpressionInferencesJsx.tsx, 14, 2)) + + [key: string]: { value: number } & ( +>key : Symbol(key, Decl(intraExpressionInferencesJsx.tsx, 17, 3)) +>value : Symbol(value, Decl(intraExpressionInferencesJsx.tsx, 17, 18)) + + | ({ kind: "a"; func?(): Partial } & A) +>kind : Symbol(kind, Decl(intraExpressionInferencesJsx.tsx, 18, 8)) +>func : Symbol(func, Decl(intraExpressionInferencesJsx.tsx, 18, 19)) +>Partial : Symbol(Partial, Decl(lib.es5.d.ts, --, --)) +>A : Symbol(A, Decl(intraExpressionInferencesJsx.tsx, 0, 0)) +>A : Symbol(A, Decl(intraExpressionInferencesJsx.tsx, 0, 0)) + + | ({ kind: "b"; func?(): Partial } & B) +>kind : Symbol(kind, Decl(intraExpressionInferencesJsx.tsx, 19, 8)) +>func : Symbol(func, Decl(intraExpressionInferencesJsx.tsx, 19, 19)) +>Partial : Symbol(Partial, Decl(lib.es5.d.ts, --, --)) +>B : Symbol(B, Decl(intraExpressionInferencesJsx.tsx, 6, 2)) +>B : Symbol(B, Decl(intraExpressionInferencesJsx.tsx, 6, 2)) + + | ({ kind: "c"; func?(): Partial } & C) +>kind : Symbol(kind, Decl(intraExpressionInferencesJsx.tsx, 20, 8)) +>func : Symbol(func, Decl(intraExpressionInferencesJsx.tsx, 20, 19)) +>Partial : Symbol(Partial, Decl(lib.es5.d.ts, --, --)) +>C : Symbol(C, Decl(intraExpressionInferencesJsx.tsx, 10, 2)) +>C : Symbol(C, Decl(intraExpressionInferencesJsx.tsx, 10, 2)) + + ); +}; + +type StyleParam = Record; +>StyleParam : Symbol(StyleParam, Decl(intraExpressionInferencesJsx.tsx, 22, 2)) +>T : Symbol(T, Decl(intraExpressionInferencesJsx.tsx, 24, 16)) +>Animations : Symbol(Animations, Decl(intraExpressionInferencesJsx.tsx, 14, 2)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(intraExpressionInferencesJsx.tsx, 24, 16)) + +type AnimatedViewProps = { +>AnimatedViewProps : Symbol(AnimatedViewProps, Decl(intraExpressionInferencesJsx.tsx, 24, 64)) +>T : Symbol(T, Decl(intraExpressionInferencesJsx.tsx, 26, 23)) +>Animations : Symbol(Animations, Decl(intraExpressionInferencesJsx.tsx, 14, 2)) + + style: (animationsValues: StyleParam) => string; +>style : Symbol(style, Decl(intraExpressionInferencesJsx.tsx, 26, 48)) +>animationsValues : Symbol(animationsValues, Decl(intraExpressionInferencesJsx.tsx, 27, 10)) +>StyleParam : Symbol(StyleParam, Decl(intraExpressionInferencesJsx.tsx, 22, 2)) +>T : Symbol(T, Decl(intraExpressionInferencesJsx.tsx, 26, 23)) + + animations: T; +>animations : Symbol(animations, Decl(intraExpressionInferencesJsx.tsx, 27, 53)) +>T : Symbol(T, Decl(intraExpressionInferencesJsx.tsx, 26, 23)) + +}; + +const Component = ({ +>Component : Symbol(Component, Decl(intraExpressionInferencesJsx.tsx, 31, 5)) +>T : Symbol(T, Decl(intraExpressionInferencesJsx.tsx, 31, 19)) +>Animations : Symbol(Animations, Decl(intraExpressionInferencesJsx.tsx, 14, 2)) + + animations, +>animations : Symbol(animations, Decl(intraExpressionInferencesJsx.tsx, 31, 42)) + + style, +>style : Symbol(style, Decl(intraExpressionInferencesJsx.tsx, 32, 13)) + +}: AnimatedViewProps) => <>; +>AnimatedViewProps : Symbol(AnimatedViewProps, Decl(intraExpressionInferencesJsx.tsx, 24, 64)) +>T : Symbol(T, Decl(intraExpressionInferencesJsx.tsx, 31, 19)) + +Component : Symbol(Component, Decl(intraExpressionInferencesJsx.tsx, 31, 5)) + + animations={{ +>animations : Symbol(animations, Decl(intraExpressionInferencesJsx.tsx, 36, 10)) + + test: { +>test : Symbol(test, Decl(intraExpressionInferencesJsx.tsx, 37, 15)) + + kind: "a", +>kind : Symbol(kind, Decl(intraExpressionInferencesJsx.tsx, 38, 11)) + + value: 1, +>value : Symbol(value, Decl(intraExpressionInferencesJsx.tsx, 39, 16)) + + a: true, +>a : Symbol(a, Decl(intraExpressionInferencesJsx.tsx, 40, 15)) + + }, + }} + style={(anim) => { +>style : Symbol(style, Decl(intraExpressionInferencesJsx.tsx, 43, 4)) +>anim : Symbol(anim, Decl(intraExpressionInferencesJsx.tsx, 44, 10)) + + return ""; + }} +/>; +Component : Symbol(Component, Decl(intraExpressionInferencesJsx.tsx, 31, 5)) + + animations={{ +>animations : Symbol(animations, Decl(intraExpressionInferencesJsx.tsx, 48, 10)) + + test: { +>test : Symbol(test, Decl(intraExpressionInferencesJsx.tsx, 49, 15)) + + kind: "a", +>kind : Symbol(kind, Decl(intraExpressionInferencesJsx.tsx, 50, 11)) + + value: 1, +>value : Symbol(value, Decl(intraExpressionInferencesJsx.tsx, 51, 16)) + + a: true, +>a : Symbol(a, Decl(intraExpressionInferencesJsx.tsx, 52, 15)) + + func() { +>func : Symbol(func, Decl(intraExpressionInferencesJsx.tsx, 53, 14)) + + return { + a: true, +>a : Symbol(a, Decl(intraExpressionInferencesJsx.tsx, 55, 16)) + + }; + }, + }, + }} + style={(anim) => { +>style : Symbol(style, Decl(intraExpressionInferencesJsx.tsx, 60, 4)) +>anim : Symbol(anim, Decl(intraExpressionInferencesJsx.tsx, 61, 10)) + + return ""; + }} +/>; +Component : Symbol(Component, Decl(intraExpressionInferencesJsx.tsx, 31, 5)) + + animations={{ +>animations : Symbol(animations, Decl(intraExpressionInferencesJsx.tsx, 65, 10)) + + test: { +>test : Symbol(test, Decl(intraExpressionInferencesJsx.tsx, 66, 15)) + + kind: "a", +>kind : Symbol(kind, Decl(intraExpressionInferencesJsx.tsx, 67, 11)) + + value: 1, +>value : Symbol(value, Decl(intraExpressionInferencesJsx.tsx, 68, 16)) + + a: true, +>a : Symbol(a, Decl(intraExpressionInferencesJsx.tsx, 69, 15)) + + func: () => { +>func : Symbol(func, Decl(intraExpressionInferencesJsx.tsx, 70, 14)) + + return { + a: true, +>a : Symbol(a, Decl(intraExpressionInferencesJsx.tsx, 72, 16)) + + }; + }, + }, + }} + style={(anim) => { +>style : Symbol(style, Decl(intraExpressionInferencesJsx.tsx, 77, 4)) +>anim : Symbol(anim, Decl(intraExpressionInferencesJsx.tsx, 78, 10)) + + return ""; + }} +/>; + +// repro from #52786 + +interface Props { +>Props : Symbol(Props, Decl(intraExpressionInferencesJsx.tsx, 81, 3)) +>T : Symbol(T, Decl(intraExpressionInferencesJsx.tsx, 85, 16)) + + a: (x: string) => T; +>a : Symbol(Props.a, Decl(intraExpressionInferencesJsx.tsx, 85, 20)) +>x : Symbol(x, Decl(intraExpressionInferencesJsx.tsx, 86, 6)) +>T : Symbol(T, Decl(intraExpressionInferencesJsx.tsx, 85, 16)) + + b: (arg: T) => void; +>b : Symbol(Props.b, Decl(intraExpressionInferencesJsx.tsx, 86, 22)) +>arg : Symbol(arg, Decl(intraExpressionInferencesJsx.tsx, 87, 6)) +>T : Symbol(T, Decl(intraExpressionInferencesJsx.tsx, 85, 16)) +} + +function Foo(props: Props) { +>Foo : Symbol(Foo, Decl(intraExpressionInferencesJsx.tsx, 88, 1)) +>T : Symbol(T, Decl(intraExpressionInferencesJsx.tsx, 90, 13)) +>props : Symbol(props, Decl(intraExpressionInferencesJsx.tsx, 90, 16)) +>Props : Symbol(Props, Decl(intraExpressionInferencesJsx.tsx, 81, 3)) +>T : Symbol(T, Decl(intraExpressionInferencesJsx.tsx, 90, 13)) + + return
; +>div : Symbol(JSX.IntrinsicElements.div, Decl(react16.d.ts, 2546, 114)) +} + +Foo : Symbol(Foo, Decl(intraExpressionInferencesJsx.tsx, 88, 1)) + + a={() => 10} +>a : Symbol(a, Decl(intraExpressionInferencesJsx.tsx, 94, 4)) + + b={(arg) => { arg.toString(); }} +>b : Symbol(b, Decl(intraExpressionInferencesJsx.tsx, 95, 14)) +>arg : Symbol(arg, Decl(intraExpressionInferencesJsx.tsx, 96, 6)) +>arg.toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) +>arg : Symbol(arg, Decl(intraExpressionInferencesJsx.tsx, 96, 6)) +>toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) + +/>; + +Foo : Symbol(Foo, Decl(intraExpressionInferencesJsx.tsx, 88, 1)) + + a={(x) => 10} +>a : Symbol(a, Decl(intraExpressionInferencesJsx.tsx, 99, 4)) +>x : Symbol(x, Decl(intraExpressionInferencesJsx.tsx, 100, 6)) + + b={(arg) => { arg.toString(); }} +>b : Symbol(b, Decl(intraExpressionInferencesJsx.tsx, 100, 15)) +>arg : Symbol(arg, Decl(intraExpressionInferencesJsx.tsx, 101, 6)) +>arg.toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) +>arg : Symbol(arg, Decl(intraExpressionInferencesJsx.tsx, 101, 6)) +>toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) + +/>; + +Foo : Symbol(Foo, Decl(intraExpressionInferencesJsx.tsx, 88, 1)) + + a: (x) => 10, +>a : Symbol(a, Decl(intraExpressionInferencesJsx.tsx, 104, 10)) +>x : Symbol(x, Decl(intraExpressionInferencesJsx.tsx, 105, 6)) + + b: (arg) => { arg.toString(); }, +>b : Symbol(b, Decl(intraExpressionInferencesJsx.tsx, 105, 15)) +>arg : Symbol(arg, Decl(intraExpressionInferencesJsx.tsx, 106, 6)) +>arg.toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) +>arg : Symbol(arg, Decl(intraExpressionInferencesJsx.tsx, 106, 6)) +>toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) + +}} />; + diff --git a/tests/baselines/reference/intraExpressionInferencesJsx.types b/tests/baselines/reference/intraExpressionInferencesJsx.types new file mode 100644 index 0000000000000..642809682ecf5 --- /dev/null +++ b/tests/baselines/reference/intraExpressionInferencesJsx.types @@ -0,0 +1,297 @@ +=== tests/cases/conformance/types/typeRelationships/typeInference/intraExpressionInferencesJsx.tsx === +/// + +// repro from #52798 + +type A = { +>A : { a: boolean; } + + a: boolean; +>a : boolean + +}; + +type B = { +>B : { b: string; } + + b: string; +>b : string + +}; + +type C = { +>C : { c: number; } + + c: number; +>c : number + +}; + +type Animations = { +>Animations : { [key: string]: { value: number; } & (({ kind: "a"; func?(): Partial; } & A) | ({ kind: "b"; func?(): Partial; } & B) | ({ kind: "c"; func?(): Partial; } & C)); } + + [key: string]: { value: number } & ( +>key : string +>value : number + + | ({ kind: "a"; func?(): Partial } & A) +>kind : "a" +>func : (() => Partial) | undefined + + | ({ kind: "b"; func?(): Partial } & B) +>kind : "b" +>func : (() => Partial) | undefined + + | ({ kind: "c"; func?(): Partial } & C) +>kind : "c" +>func : (() => Partial) | undefined + + ); +}; + +type StyleParam = Record; +>StyleParam : StyleParam + +type AnimatedViewProps = { +>AnimatedViewProps : AnimatedViewProps + + style: (animationsValues: StyleParam) => string; +>style : (animationsValues: StyleParam) => string +>animationsValues : StyleParam + + animations: T; +>animations : T + +}; + +const Component = ({ +>Component : ({ animations, style, }: AnimatedViewProps) => JSX.Element +>({ animations, style,}: AnimatedViewProps) => <> : ({ animations, style, }: AnimatedViewProps) => JSX.Element + + animations, +>animations : T + + style, +>style : (animationsValues: StyleParam) => string + +}: AnimatedViewProps) => <>; +><> : JSX.Element + + { return ""; }}/> : JSX.Element +>Component : ({ animations, style, }: AnimatedViewProps) => JSX.Element + + animations={{ +>animations : { test: { kind: "a"; value: number; a: true; }; } +>{ test: { kind: "a", value: 1, a: true, }, } : { test: { kind: "a"; value: number; a: true; }; } + + test: { +>test : { kind: "a"; value: number; a: true; } +>{ kind: "a", value: 1, a: true, } : { kind: "a"; value: number; a: true; } + + kind: "a", +>kind : "a" +>"a" : "a" + + value: 1, +>value : number +>1 : 1 + + a: true, +>a : true +>true : true + + }, + }} + style={(anim) => { +>style : (anim: StyleParam<{ test: { kind: "a"; value: number; a: true; }; }>) => string +>(anim) => { return ""; } : (anim: StyleParam<{ test: { kind: "a"; value: number; a: true; }; }>) => string +>anim : StyleParam<{ test: { kind: "a"; value: number; a: true; }; }> + + return ""; +>"" : "" + + }} +/>; + { return ""; }}/> : JSX.Element +>Component : ({ animations, style, }: AnimatedViewProps) => JSX.Element + + animations={{ +>animations : { test: { kind: "a"; value: number; a: true; func(): { a: true; }; }; } +>{ test: { kind: "a", value: 1, a: true, func() { return { a: true, }; }, }, } : { test: { kind: "a"; value: number; a: true; func(): { a: true; }; }; } + + test: { +>test : { kind: "a"; value: number; a: true; func(): { a: true; }; } +>{ kind: "a", value: 1, a: true, func() { return { a: true, }; }, } : { kind: "a"; value: number; a: true; func(): { a: true; }; } + + kind: "a", +>kind : "a" +>"a" : "a" + + value: 1, +>value : number +>1 : 1 + + a: true, +>a : true +>true : true + + func() { +>func : () => { a: true; } + + return { +>{ a: true, } : { a: true; } + + a: true, +>a : true +>true : true + + }; + }, + }, + }} + style={(anim) => { +>style : (anim: StyleParam<{ test: { kind: "a"; value: number; a: true; func(): { a: true; }; }; }>) => string +>(anim) => { return ""; } : (anim: StyleParam<{ test: { kind: "a"; value: number; a: true; func(): { a: true; }; }; }>) => string +>anim : StyleParam<{ test: { kind: "a"; value: number; a: true; func(): { a: true; }; }; }> + + return ""; +>"" : "" + + }} +/>; + { return { a: true, }; }, }, }} style={(anim) => { return ""; }}/> : JSX.Element +>Component : ({ animations, style, }: AnimatedViewProps) => JSX.Element + + animations={{ +>animations : { test: { kind: "a"; value: number; a: true; func: () => { a: true; }; }; } +>{ test: { kind: "a", value: 1, a: true, func: () => { return { a: true, }; }, }, } : { test: { kind: "a"; value: number; a: true; func: () => { a: true; }; }; } + + test: { +>test : { kind: "a"; value: number; a: true; func: () => { a: true; }; } +>{ kind: "a", value: 1, a: true, func: () => { return { a: true, }; }, } : { kind: "a"; value: number; a: true; func: () => { a: true; }; } + + kind: "a", +>kind : "a" +>"a" : "a" + + value: 1, +>value : number +>1 : 1 + + a: true, +>a : true +>true : true + + func: () => { +>func : () => { a: true; } +>() => { return { a: true, }; } : () => { a: true; } + + return { +>{ a: true, } : { a: true; } + + a: true, +>a : true +>true : true + + }; + }, + }, + }} + style={(anim) => { +>style : (anim: StyleParam<{ test: { kind: "a"; value: number; a: true; func: () => { a: true; }; }; }>) => string +>(anim) => { return ""; } : (anim: StyleParam<{ test: { kind: "a"; value: number; a: true; func: () => { a: true; }; }; }>) => string +>anim : StyleParam<{ test: { kind: "a"; value: number; a: true; func: () => { a: true; }; }; }> + + return ""; +>"" : "" + + }} +/>; + +// repro from #52786 + +interface Props { + a: (x: string) => T; +>a : (x: string) => T +>x : string + + b: (arg: T) => void; +>b : (arg: T) => void +>arg : T +} + +function Foo(props: Props) { +>Foo : (props: Props) => JSX.Element +>props : Props + + return
; +>
: JSX.Element +>div : any +} + + 10} b={(arg) => { arg.toString(); }}/> : JSX.Element +>Foo : (props: Props) => JSX.Element + + a={() => 10} +>a : () => number +>() => 10 : () => number +>10 : 10 + + b={(arg) => { arg.toString(); }} +>b : (arg: number) => void +>(arg) => { arg.toString(); } : (arg: number) => void +>arg : number +>arg.toString() : string +>arg.toString : (radix?: number | undefined) => string +>arg : number +>toString : (radix?: number | undefined) => string + +/>; + + 10} b={(arg) => { arg.toString(); }}/> : JSX.Element +>Foo : (props: Props) => JSX.Element + + a={(x) => 10} +>a : (x: string) => number +>(x) => 10 : (x: string) => number +>x : string +>10 : 10 + + b={(arg) => { arg.toString(); }} +>b : (arg: number) => void +>(arg) => { arg.toString(); } : (arg: number) => void +>arg : number +>arg.toString() : string +>arg.toString : (radix?: number | undefined) => string +>arg : number +>toString : (radix?: number | undefined) => string + +/>; + + 10, b: (arg) => { arg.toString(); },}} /> : JSX.Element +>Foo : (props: Props) => JSX.Element +>{ a: (x) => 10, b: (arg) => { arg.toString(); },} : { a: (x: string) => number; b: (arg: number) => void; } + + a: (x) => 10, +>a : (x: string) => number +>(x) => 10 : (x: string) => number +>x : string +>10 : 10 + + b: (arg) => { arg.toString(); }, +>b : (arg: number) => void +>(arg) => { arg.toString(); } : (arg: number) => void +>arg : number +>arg.toString() : string +>arg.toString : (radix?: number | undefined) => string +>arg : number +>toString : (radix?: number | undefined) => string + +}} />; + diff --git a/tests/cases/conformance/types/typeRelationships/typeInference/intraExpressionInferencesJsx.tsx b/tests/cases/conformance/types/typeRelationships/typeInference/intraExpressionInferencesJsx.tsx new file mode 100644 index 0000000000000..4ecd4f9e4b62f --- /dev/null +++ b/tests/cases/conformance/types/typeRelationships/typeInference/intraExpressionInferencesJsx.tsx @@ -0,0 +1,112 @@ +// @strict: true +// @jsx: react-jsx +// @noEmit: true + +/// + +// repro from #52798 + +type A = { + a: boolean; +}; + +type B = { + b: string; +}; + +type C = { + c: number; +}; + +type Animations = { + [key: string]: { value: number } & ( + | ({ kind: "a"; func?(): Partial } & A) + | ({ kind: "b"; func?(): Partial } & B) + | ({ kind: "c"; func?(): Partial } & C) + ); +}; + +type StyleParam = Record; + +type AnimatedViewProps = { + style: (animationsValues: StyleParam) => string; + animations: T; +}; + +const Component = ({ + animations, + style, +}: AnimatedViewProps) => <>; + + { + return ""; + }} +/>; + { + return ""; + }} +/>; + { + return { + a: true, + }; + }, + }, + }} + style={(anim) => { + return ""; + }} +/>; + +// repro from #52786 + +interface Props { + a: (x: string) => T; + b: (arg: T) => void; +} + +function Foo(props: Props) { + return
; +} + + 10} + b={(arg) => { arg.toString(); }} +/>; + + 10} + b={(arg) => { arg.toString(); }} +/>; + + 10, + b: (arg) => { arg.toString(); }, +}} />;