From 4ea8ec49e8aed6601fb6b978fd08031ec058da04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Fri, 18 Nov 2022 00:36:12 +0100 Subject: [PATCH 1/2] Fixed an issue with spreading a spreadable generic expression into generic JSX --- src/compiler/checker.ts | 2 +- ...StringLiteralsInJsxAttributes02.errors.txt | 4 +- ...thSpreadingResultOfGenericFunction.symbols | 47 +++++++++++++++++++ ...WithSpreadingResultOfGenericFunction.types | 36 ++++++++++++++ ...ntWithSpreadingResultOfGenericFunction.tsx | 18 +++++++ 5 files changed, 104 insertions(+), 3 deletions(-) create mode 100644 tests/baselines/reference/jsxGenericComponentWithSpreadingResultOfGenericFunction.symbols create mode 100644 tests/baselines/reference/jsxGenericComponentWithSpreadingResultOfGenericFunction.types create mode 100644 tests/cases/compiler/jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 467b91cbe4d4b..4de3d9e86f995 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -28781,7 +28781,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { spread = getSpreadType(spread, createJsxAttributesType(), attributes.symbol, objectFlags, /*readonly*/ false); attributesTable = createSymbolTable(); } - const exprType = getReducedType(checkExpressionCached(attributeDecl.expression, checkMode)); + const exprType = getReducedType(checkExpressionCached(attributeDecl.expression)); if (isTypeAny(exprType)) { hasSpreadAnyType = true; } diff --git a/tests/baselines/reference/contextuallyTypedStringLiteralsInJsxAttributes02.errors.txt b/tests/baselines/reference/contextuallyTypedStringLiteralsInJsxAttributes02.errors.txt index b66975fdb731e..b91241681ba42 100644 --- a/tests/baselines/reference/contextuallyTypedStringLiteralsInJsxAttributes02.errors.txt +++ b/tests/baselines/reference/contextuallyTypedStringLiteralsInJsxAttributes02.errors.txt @@ -17,7 +17,7 @@ tests/cases/conformance/types/contextualTypes/jsxAttributes/file.tsx(29,43): err Type '{ extra: true; goTo: string; }' is not assignable to type 'IntrinsicAttributes & ButtonProps'. Property 'extra' does not exist on type 'IntrinsicAttributes & ButtonProps'. Overload 2 of 2, '(linkProps: LinkProps): Element', gave the following error. - Type '{ extra: true; goTo: "home"; }' is not assignable to type 'IntrinsicAttributes & LinkProps'. + Type '{ extra: true; goTo: string; }' is not assignable to type 'IntrinsicAttributes & LinkProps'. Property 'extra' does not exist on type 'IntrinsicAttributes & LinkProps'. tests/cases/conformance/types/contextualTypes/jsxAttributes/file.tsx(30,12): error TS2769: No overload matches this call. Overload 1 of 2, '(buttonProps: ButtonProps): Element', gave the following error. @@ -84,7 +84,7 @@ tests/cases/conformance/types/contextualTypes/jsxAttributes/file.tsx(36,44): err !!! error TS2769: Type '{ extra: true; goTo: string; }' is not assignable to type 'IntrinsicAttributes & ButtonProps'. !!! error TS2769: Property 'extra' does not exist on type 'IntrinsicAttributes & ButtonProps'. !!! error TS2769: Overload 2 of 2, '(linkProps: LinkProps): Element', gave the following error. -!!! error TS2769: Type '{ extra: true; goTo: "home"; }' is not assignable to type 'IntrinsicAttributes & LinkProps'. +!!! error TS2769: Type '{ extra: true; goTo: string; }' is not assignable to type 'IntrinsicAttributes & LinkProps'. !!! error TS2769: Property 'extra' does not exist on type 'IntrinsicAttributes & LinkProps'. const b4 = ; // goTo has type "home" | "contact" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/tests/baselines/reference/jsxGenericComponentWithSpreadingResultOfGenericFunction.symbols b/tests/baselines/reference/jsxGenericComponentWithSpreadingResultOfGenericFunction.symbols new file mode 100644 index 0000000000000..9a98bcaf939b1 --- /dev/null +++ b/tests/baselines/reference/jsxGenericComponentWithSpreadingResultOfGenericFunction.symbols @@ -0,0 +1,47 @@ +=== tests/cases/compiler/jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx === +/// + +// repro #51577 + +declare function omit(names: readonly K[], obj: T): Omit; +>omit : Symbol(omit, Decl(jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx, 0, 0), Decl(jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx, 4, 84)) +>T : Symbol(T, Decl(jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx, 4, 22)) +>K : Symbol(K, Decl(jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx, 4, 24)) +>names : Symbol(names, Decl(jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx, 4, 43)) +>K : Symbol(K, Decl(jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx, 4, 24)) +>obj : Symbol(obj, Decl(jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx, 4, 63)) +>T : Symbol(T, Decl(jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx, 4, 22)) +>Omit : Symbol(Omit, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx, 4, 22)) +>K : Symbol(K, Decl(jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx, 4, 24)) + +declare function omit(names: readonly K[]): (obj: T) => Omit; +>omit : Symbol(omit, Decl(jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx, 0, 0), Decl(jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx, 4, 84)) +>K : Symbol(K, Decl(jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx, 5, 22)) +>names : Symbol(names, Decl(jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx, 5, 40)) +>K : Symbol(K, Decl(jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx, 5, 22)) +>T : Symbol(T, Decl(jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx, 5, 63)) +>obj : Symbol(obj, Decl(jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx, 5, 66)) +>T : Symbol(T, Decl(jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx, 5, 63)) +>Omit : Symbol(Omit, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx, 5, 63)) +>K : Symbol(K, Decl(jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx, 5, 22)) + +declare const otherProps: { bar: string, qwe: boolean } +>otherProps : Symbol(otherProps, Decl(jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx, 7, 13)) +>bar : Symbol(bar, Decl(jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx, 7, 27)) +>qwe : Symbol(qwe, Decl(jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx, 7, 40)) + +declare function GenericComponent(props: T): null +>GenericComponent : Symbol(GenericComponent, Decl(jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx, 7, 55)) +>T : Symbol(T, Decl(jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx, 9, 34)) +>props : Symbol(props, Decl(jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx, 9, 37)) +>T : Symbol(T, Decl(jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx, 9, 34)) + +; // no error +>GenericComponent : Symbol(GenericComponent, Decl(jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx, 7, 55)) +>omit : Symbol(omit, Decl(jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx, 0, 0), Decl(jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx, 4, 84)) +>otherProps : Symbol(otherProps, Decl(jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx, 7, 13)) + + + diff --git a/tests/baselines/reference/jsxGenericComponentWithSpreadingResultOfGenericFunction.types b/tests/baselines/reference/jsxGenericComponentWithSpreadingResultOfGenericFunction.types new file mode 100644 index 0000000000000..7d6093bcd9efb --- /dev/null +++ b/tests/baselines/reference/jsxGenericComponentWithSpreadingResultOfGenericFunction.types @@ -0,0 +1,36 @@ +=== tests/cases/compiler/jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx === +/// + +// repro #51577 + +declare function omit(names: readonly K[], obj: T): Omit; +>omit : { (names: readonly K[], obj: T): Omit; (names: readonly K[]): (obj: T) => Omit; } +>names : readonly K[] +>obj : T + +declare function omit(names: readonly K[]): (obj: T) => Omit; +>omit : { (names: readonly K[], obj: T): Omit; (names: readonly K[]): (obj: T) => Omit; } +>names : readonly K[] +>obj : T + +declare const otherProps: { bar: string, qwe: boolean } +>otherProps : { bar: string; qwe: boolean; } +>bar : string +>qwe : boolean + +declare function GenericComponent(props: T): null +>GenericComponent : (props: T) => null +>props : T +>null : null + +; // no error +> : JSX.Element +>GenericComponent : (props: T) => null +>omit(['bar'], otherProps) : Omit<{ bar: string; qwe: boolean; }, "bar"> +>omit : { (names: readonly K[], obj: T): Omit; (names: readonly K[]): (obj: T) => Omit; } +>['bar'] : "bar"[] +>'bar' : "bar" +>otherProps : { bar: string; qwe: boolean; } + + + diff --git a/tests/cases/compiler/jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx b/tests/cases/compiler/jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx new file mode 100644 index 0000000000000..abb94add5e62a --- /dev/null +++ b/tests/cases/compiler/jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx @@ -0,0 +1,18 @@ +// @strict: true +// @noEmit: true +// @jsx: preserve + +/// + +// repro #51577 + +declare function omit(names: readonly K[], obj: T): Omit; +declare function omit(names: readonly K[]): (obj: T) => Omit; + +declare const otherProps: { bar: string, qwe: boolean } + +declare function GenericComponent(props: T): null + +; // no error + + From 1c00498c63c4c00a380a0e3247fd38ed98d6c550 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Fri, 18 Nov 2022 01:12:40 +0100 Subject: [PATCH 2/2] Avoid caching too to avoid resolved type to carry over from unmatched overload --- src/compiler/checker.ts | 2 +- ...ontextuallyTypedStringLiteralsInJsxAttributes02.errors.txt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 4de3d9e86f995..97fdc0aa0537f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -28781,7 +28781,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { spread = getSpreadType(spread, createJsxAttributesType(), attributes.symbol, objectFlags, /*readonly*/ false); attributesTable = createSymbolTable(); } - const exprType = getReducedType(checkExpressionCached(attributeDecl.expression)); + const exprType = getReducedType(checkExpression(attributeDecl.expression)); if (isTypeAny(exprType)) { hasSpreadAnyType = true; } diff --git a/tests/baselines/reference/contextuallyTypedStringLiteralsInJsxAttributes02.errors.txt b/tests/baselines/reference/contextuallyTypedStringLiteralsInJsxAttributes02.errors.txt index b91241681ba42..b66975fdb731e 100644 --- a/tests/baselines/reference/contextuallyTypedStringLiteralsInJsxAttributes02.errors.txt +++ b/tests/baselines/reference/contextuallyTypedStringLiteralsInJsxAttributes02.errors.txt @@ -17,7 +17,7 @@ tests/cases/conformance/types/contextualTypes/jsxAttributes/file.tsx(29,43): err Type '{ extra: true; goTo: string; }' is not assignable to type 'IntrinsicAttributes & ButtonProps'. Property 'extra' does not exist on type 'IntrinsicAttributes & ButtonProps'. Overload 2 of 2, '(linkProps: LinkProps): Element', gave the following error. - Type '{ extra: true; goTo: string; }' is not assignable to type 'IntrinsicAttributes & LinkProps'. + Type '{ extra: true; goTo: "home"; }' is not assignable to type 'IntrinsicAttributes & LinkProps'. Property 'extra' does not exist on type 'IntrinsicAttributes & LinkProps'. tests/cases/conformance/types/contextualTypes/jsxAttributes/file.tsx(30,12): error TS2769: No overload matches this call. Overload 1 of 2, '(buttonProps: ButtonProps): Element', gave the following error. @@ -84,7 +84,7 @@ tests/cases/conformance/types/contextualTypes/jsxAttributes/file.tsx(36,44): err !!! error TS2769: Type '{ extra: true; goTo: string; }' is not assignable to type 'IntrinsicAttributes & ButtonProps'. !!! error TS2769: Property 'extra' does not exist on type 'IntrinsicAttributes & ButtonProps'. !!! error TS2769: Overload 2 of 2, '(linkProps: LinkProps): Element', gave the following error. -!!! error TS2769: Type '{ extra: true; goTo: string; }' is not assignable to type 'IntrinsicAttributes & LinkProps'. +!!! error TS2769: Type '{ extra: true; goTo: "home"; }' is not assignable to type 'IntrinsicAttributes & LinkProps'. !!! error TS2769: Property 'extra' does not exist on type 'IntrinsicAttributes & LinkProps'. const b4 = ; // goTo has type "home" | "contact" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~