From c8d92fa9720f623038192358a2d8c6bce2bc087c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Sun, 15 Sep 2024 11:40:23 +0200 Subject: [PATCH] Fixed single signature type instantiations leaking between calls with different mappers --- src/compiler/checker.ts | 12 +- ...icCallInferenceInConditionalTypes1.symbols | 173 ++++++++++++++++++ ...ericCallInferenceInConditionalTypes1.types | 151 +++++++++++++++ ...lInferenceWithGenericLocalFunction.symbols | 57 ++++++ ...allInferenceWithGenericLocalFunction.types | 125 +++++++++++++ ...genericCallInferenceInConditionalTypes1.ts | 59 ++++++ ...icCallInferenceWithGenericLocalFunction.ts | 15 ++ 7 files changed, 585 insertions(+), 7 deletions(-) create mode 100644 tests/baselines/reference/genericCallInferenceInConditionalTypes1.symbols create mode 100644 tests/baselines/reference/genericCallInferenceInConditionalTypes1.types create mode 100644 tests/cases/compiler/genericCallInferenceInConditionalTypes1.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 4d4f1bf69a808..91eada90e3ded 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -20218,7 +20218,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const links = getNodeLinks(declaration); const target = type.objectFlags & ObjectFlags.Reference ? links.resolvedType! as DeferredTypeReference : type.objectFlags & ObjectFlags.Instantiated ? type.target! : type; - let typeParameters = type.objectFlags & ObjectFlags.SingleSignatureType ? (type as SingleSignatureType).outerTypeParameters : links.outerTypeParameters; + let typeParameters = links.outerTypeParameters; if (!typeParameters) { // The first time an anonymous type is instantiated we compute and store a list of the type // parameters that are in scope (and therefore potentially referenced). For type literals that @@ -20244,18 +20244,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const typeArguments = map(typeParameters, t => getMappedType(t, combinedMapper)); const newAliasSymbol = aliasSymbol || type.aliasSymbol; const newAliasTypeArguments = aliasSymbol ? aliasTypeArguments : instantiateTypes(type.aliasTypeArguments, mapper); - const id = (type.objectFlags & ObjectFlags.SingleSignatureType ? "S" : "") + getTypeListId(typeArguments) + getAliasId(newAliasSymbol, newAliasTypeArguments); + const id = getTypeListId(typeArguments) + getAliasId(newAliasSymbol, newAliasTypeArguments); if (!target.instantiations) { target.instantiations = new Map(); target.instantiations.set(getTypeListId(typeParameters) + getAliasId(target.aliasSymbol, target.aliasTypeArguments), target); } let result = target.instantiations.get(id); if (!result) { - if (type.objectFlags & ObjectFlags.SingleSignatureType) { - result = instantiateAnonymousType(type, mapper); - target.instantiations.set(id, result); - return result; - } const newMapper = createTypeMapper(typeParameters, typeArguments); result = target.objectFlags & ObjectFlags.Reference ? createDeferredTypeReference((type as DeferredTypeReference).target, (type as DeferredTypeReference).node, newMapper, newAliasSymbol, newAliasTypeArguments) : target.objectFlags & ObjectFlags.Mapped ? instantiateMappedType(target as MappedType, newMapper, newAliasSymbol, newAliasTypeArguments) : @@ -20533,6 +20528,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (objectFlags & ObjectFlags.ReverseMapped) { return instantiateReverseMappedType(type as ReverseMappedType, mapper); } + if (objectFlags & ObjectFlags.SingleSignatureType) { + return instantiateAnonymousType(type as SingleSignatureType, mapper); + } return getObjectTypeInstantiation(type as TypeReference | AnonymousType | MappedType, mapper, aliasSymbol, aliasTypeArguments); } return type; diff --git a/tests/baselines/reference/genericCallInferenceInConditionalTypes1.symbols b/tests/baselines/reference/genericCallInferenceInConditionalTypes1.symbols new file mode 100644 index 0000000000000..7332aa25baa12 --- /dev/null +++ b/tests/baselines/reference/genericCallInferenceInConditionalTypes1.symbols @@ -0,0 +1,173 @@ +//// [tests/cases/compiler/genericCallInferenceInConditionalTypes1.ts] //// + +=== genericCallInferenceInConditionalTypes1.ts === +// https://github.com/microsoft/TypeScript/issues/59937 + +type Ref = { +>Ref : Symbol(Ref, Decl(genericCallInferenceInConditionalTypes1.ts, 0, 0)) +>T : Symbol(T, Decl(genericCallInferenceInConditionalTypes1.ts, 2, 9)) + + current: T; +>current : Symbol(current, Decl(genericCallInferenceInConditionalTypes1.ts, 2, 15)) +>T : Symbol(T, Decl(genericCallInferenceInConditionalTypes1.ts, 2, 9)) + +}; + +type FunctionComponent

= (props: P) => unknown; +>FunctionComponent : Symbol(FunctionComponent, Decl(genericCallInferenceInConditionalTypes1.ts, 4, 2)) +>P : Symbol(P, Decl(genericCallInferenceInConditionalTypes1.ts, 6, 23)) +>props : Symbol(props, Decl(genericCallInferenceInConditionalTypes1.ts, 6, 29)) +>P : Symbol(P, Decl(genericCallInferenceInConditionalTypes1.ts, 6, 23)) + +type ComponentProps> = +>ComponentProps : Symbol(ComponentProps, Decl(genericCallInferenceInConditionalTypes1.ts, 6, 50)) +>T : Symbol(T, Decl(genericCallInferenceInConditionalTypes1.ts, 8, 20)) +>FunctionComponent : Symbol(FunctionComponent, Decl(genericCallInferenceInConditionalTypes1.ts, 4, 2)) + + T extends FunctionComponent ? P : {}; +>T : Symbol(T, Decl(genericCallInferenceInConditionalTypes1.ts, 8, 20)) +>FunctionComponent : Symbol(FunctionComponent, Decl(genericCallInferenceInConditionalTypes1.ts, 4, 2)) +>P : Symbol(P, Decl(genericCallInferenceInConditionalTypes1.ts, 9, 35)) +>P : Symbol(P, Decl(genericCallInferenceInConditionalTypes1.ts, 9, 35)) + +type PropsWithoutRef

= P extends any +>PropsWithoutRef : Symbol(PropsWithoutRef, Decl(genericCallInferenceInConditionalTypes1.ts, 9, 48)) +>P : Symbol(P, Decl(genericCallInferenceInConditionalTypes1.ts, 11, 21)) +>P : Symbol(P, Decl(genericCallInferenceInConditionalTypes1.ts, 11, 21)) + + ? "ref" extends keyof P +>P : Symbol(P, Decl(genericCallInferenceInConditionalTypes1.ts, 11, 21)) + + ? Omit +>Omit : Symbol(Omit, Decl(lib.es5.d.ts, --, --)) +>P : Symbol(P, Decl(genericCallInferenceInConditionalTypes1.ts, 11, 21)) + + : P +>P : Symbol(P, Decl(genericCallInferenceInConditionalTypes1.ts, 11, 21)) + + : P; +>P : Symbol(P, Decl(genericCallInferenceInConditionalTypes1.ts, 11, 21)) + +type ComponentPropsWithoutRef> = +>ComponentPropsWithoutRef : Symbol(ComponentPropsWithoutRef, Decl(genericCallInferenceInConditionalTypes1.ts, 15, 6)) +>T : Symbol(T, Decl(genericCallInferenceInConditionalTypes1.ts, 17, 30)) +>FunctionComponent : Symbol(FunctionComponent, Decl(genericCallInferenceInConditionalTypes1.ts, 4, 2)) + + PropsWithoutRef>; +>PropsWithoutRef : Symbol(PropsWithoutRef, Decl(genericCallInferenceInConditionalTypes1.ts, 9, 48)) +>ComponentProps : Symbol(ComponentProps, Decl(genericCallInferenceInConditionalTypes1.ts, 6, 50)) +>T : Symbol(T, Decl(genericCallInferenceInConditionalTypes1.ts, 17, 30)) + +declare function forwardRef( +>forwardRef : Symbol(forwardRef, Decl(genericCallInferenceInConditionalTypes1.ts, 18, 37)) +>T : Symbol(T, Decl(genericCallInferenceInConditionalTypes1.ts, 20, 28)) +>P : Symbol(P, Decl(genericCallInferenceInConditionalTypes1.ts, 20, 30)) + + component: (props: P, ref: Ref) => unknown, +>component : Symbol(component, Decl(genericCallInferenceInConditionalTypes1.ts, 20, 34)) +>props : Symbol(props, Decl(genericCallInferenceInConditionalTypes1.ts, 21, 14)) +>P : Symbol(P, Decl(genericCallInferenceInConditionalTypes1.ts, 20, 30)) +>ref : Symbol(ref, Decl(genericCallInferenceInConditionalTypes1.ts, 21, 23)) +>Ref : Symbol(Ref, Decl(genericCallInferenceInConditionalTypes1.ts, 0, 0)) +>T : Symbol(T, Decl(genericCallInferenceInConditionalTypes1.ts, 20, 28)) + +): (props: P & { ref?: Ref }) => unknown; +>props : Symbol(props, Decl(genericCallInferenceInConditionalTypes1.ts, 22, 4)) +>P : Symbol(P, Decl(genericCallInferenceInConditionalTypes1.ts, 20, 30)) +>ref : Symbol(ref, Decl(genericCallInferenceInConditionalTypes1.ts, 22, 16)) +>Ref : Symbol(Ref, Decl(genericCallInferenceInConditionalTypes1.ts, 0, 0)) +>T : Symbol(T, Decl(genericCallInferenceInConditionalTypes1.ts, 20, 28)) + +const ComponentWithForwardRef = forwardRef( +>ComponentWithForwardRef : Symbol(ComponentWithForwardRef, Decl(genericCallInferenceInConditionalTypes1.ts, 24, 5)) +>forwardRef : Symbol(forwardRef, Decl(genericCallInferenceInConditionalTypes1.ts, 18, 37)) + + >( +>T : Symbol(T, Decl(genericCallInferenceInConditionalTypes1.ts, 25, 3)) +>FunctionComponent : Symbol(FunctionComponent, Decl(genericCallInferenceInConditionalTypes1.ts, 4, 2)) + + props: ComponentPropsWithoutRef, +>props : Symbol(props, Decl(genericCallInferenceInConditionalTypes1.ts, 25, 37)) +>ComponentPropsWithoutRef : Symbol(ComponentPropsWithoutRef, Decl(genericCallInferenceInConditionalTypes1.ts, 15, 6)) +>T : Symbol(T, Decl(genericCallInferenceInConditionalTypes1.ts, 25, 3)) + + ref: Ref, +>ref : Symbol(ref, Decl(genericCallInferenceInConditionalTypes1.ts, 26, 39)) +>Ref : Symbol(Ref, Decl(genericCallInferenceInConditionalTypes1.ts, 0, 0)) +>HTMLElement : Symbol(HTMLElement, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --)) + + ) => { + return null; + }, +); + +type Test = T extends { component?: infer Component } +>Test : Symbol(Test, Decl(genericCallInferenceInConditionalTypes1.ts, 31, 2)) +>T : Symbol(T, Decl(genericCallInferenceInConditionalTypes1.ts, 33, 10)) +>T : Symbol(T, Decl(genericCallInferenceInConditionalTypes1.ts, 33, 10)) +>component : Symbol(component, Decl(genericCallInferenceInConditionalTypes1.ts, 33, 26)) +>Component : Symbol(Component, Decl(genericCallInferenceInConditionalTypes1.ts, 33, 44)) + + ? Component extends FunctionComponent +>Component : Symbol(Component, Decl(genericCallInferenceInConditionalTypes1.ts, 33, 44)) +>FunctionComponent : Symbol(FunctionComponent, Decl(genericCallInferenceInConditionalTypes1.ts, 4, 2)) + + ? ComponentProps +>ComponentProps : Symbol(ComponentProps, Decl(genericCallInferenceInConditionalTypes1.ts, 6, 50)) +>Component : Symbol(Component, Decl(genericCallInferenceInConditionalTypes1.ts, 33, 44)) + + : never + : never; + +// the first one here has a chance to pollute the cache +type Result1 = ComponentProps; +>Result1 : Symbol(Result1, Decl(genericCallInferenceInConditionalTypes1.ts, 37, 10)) +>ComponentProps : Symbol(ComponentProps, Decl(genericCallInferenceInConditionalTypes1.ts, 6, 50)) +>ComponentWithForwardRef : Symbol(ComponentWithForwardRef, Decl(genericCallInferenceInConditionalTypes1.ts, 24, 5)) + +// that could be incorrectly reused by this one +type Result2 = Test<{ component: typeof ComponentWithForwardRef }>; // no `T` leak +>Result2 : Symbol(Result2, Decl(genericCallInferenceInConditionalTypes1.ts, 40, 62)) +>Test : Symbol(Test, Decl(genericCallInferenceInConditionalTypes1.ts, 31, 2)) +>component : Symbol(component, Decl(genericCallInferenceInConditionalTypes1.ts, 42, 21)) +>ComponentWithForwardRef : Symbol(ComponentWithForwardRef, Decl(genericCallInferenceInConditionalTypes1.ts, 24, 5)) + +// same as ComponentWithForwardRef above but using a resolved signature instead of a direct inferred result of `forwardRef` +declare const ComponentWithForwardRef2: >( +>ComponentWithForwardRef2 : Symbol(ComponentWithForwardRef2, Decl(genericCallInferenceInConditionalTypes1.ts, 45, 13)) +>T : Symbol(T, Decl(genericCallInferenceInConditionalTypes1.ts, 45, 41)) +>FunctionComponent : Symbol(FunctionComponent, Decl(genericCallInferenceInConditionalTypes1.ts, 4, 2)) + + props: PropsWithoutRef> & { +>props : Symbol(props, Decl(genericCallInferenceInConditionalTypes1.ts, 45, 75)) +>PropsWithoutRef : Symbol(PropsWithoutRef, Decl(genericCallInferenceInConditionalTypes1.ts, 9, 48)) +>ComponentProps : Symbol(ComponentProps, Decl(genericCallInferenceInConditionalTypes1.ts, 6, 50)) +>T : Symbol(T, Decl(genericCallInferenceInConditionalTypes1.ts, 45, 41)) + + className?: string; +>className : Symbol(className, Decl(genericCallInferenceInConditionalTypes1.ts, 46, 47)) + + as?: T | undefined; +>as : Symbol(as, Decl(genericCallInferenceInConditionalTypes1.ts, 47, 23)) +>T : Symbol(T, Decl(genericCallInferenceInConditionalTypes1.ts, 45, 41)) + + } & { + ref?: Ref | undefined; +>ref : Symbol(ref, Decl(genericCallInferenceInConditionalTypes1.ts, 49, 7)) +>Ref : Symbol(Ref, Decl(genericCallInferenceInConditionalTypes1.ts, 0, 0)) +>HTMLElement : Symbol(HTMLElement, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --)) + + }, +) => unknown; + +type Result3 = ComponentProps; +>Result3 : Symbol(Result3, Decl(genericCallInferenceInConditionalTypes1.ts, 52, 13)) +>ComponentProps : Symbol(ComponentProps, Decl(genericCallInferenceInConditionalTypes1.ts, 6, 50)) +>ComponentWithForwardRef2 : Symbol(ComponentWithForwardRef2, Decl(genericCallInferenceInConditionalTypes1.ts, 45, 13)) + +type Result4 = Test<{ component: typeof ComponentWithForwardRef2 }>; +>Result4 : Symbol(Result4, Decl(genericCallInferenceInConditionalTypes1.ts, 54, 63)) +>Test : Symbol(Test, Decl(genericCallInferenceInConditionalTypes1.ts, 31, 2)) +>component : Symbol(component, Decl(genericCallInferenceInConditionalTypes1.ts, 55, 21)) +>ComponentWithForwardRef2 : Symbol(ComponentWithForwardRef2, Decl(genericCallInferenceInConditionalTypes1.ts, 45, 13)) + diff --git a/tests/baselines/reference/genericCallInferenceInConditionalTypes1.types b/tests/baselines/reference/genericCallInferenceInConditionalTypes1.types new file mode 100644 index 0000000000000..0257dab6a9720 --- /dev/null +++ b/tests/baselines/reference/genericCallInferenceInConditionalTypes1.types @@ -0,0 +1,151 @@ +//// [tests/cases/compiler/genericCallInferenceInConditionalTypes1.ts] //// + +=== genericCallInferenceInConditionalTypes1.ts === +// https://github.com/microsoft/TypeScript/issues/59937 + +type Ref = { +>Ref : Ref +> : ^^^^^^ + + current: T; +>current : T +> : ^ + +}; + +type FunctionComponent

= (props: P) => unknown; +>FunctionComponent : FunctionComponent

+> : ^^^^^^^^^^^^^^^^^^^^ +>props : P +> : ^ + +type ComponentProps> = +>ComponentProps : ComponentProps +> : ^^^^^^^^^^^^^^^^^ + + T extends FunctionComponent ? P : {}; + +type PropsWithoutRef

= P extends any +>PropsWithoutRef : PropsWithoutRef

+> : ^^^^^^^^^^^^^^^^^^ + + ? "ref" extends keyof P + ? Omit + : P + : P; + +type ComponentPropsWithoutRef> = +>ComponentPropsWithoutRef : ComponentPropsWithoutRef +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + PropsWithoutRef>; + +declare function forwardRef( +>forwardRef : (component: (props: P, ref: Ref) => unknown) => (props: P & { ref?: Ref; }) => unknown +> : ^ ^^ ^^ ^^ ^^^^^ + + component: (props: P, ref: Ref) => unknown, +>component : (props: P, ref: Ref) => unknown +> : ^ ^^ ^^ ^^ ^^^^^ +>props : P +> : ^ +>ref : Ref +> : ^^^^^^ + +): (props: P & { ref?: Ref }) => unknown; +>props : P & { ref?: Ref; } +> : ^^^^^^^^^^^^ ^^^ +>ref : Ref | undefined +> : ^^^^^^^^^^^^^^^^^^ + +const ComponentWithForwardRef = forwardRef( +>ComponentWithForwardRef : >(props: PropsWithoutRef> & { ref?: Ref | undefined; }) => unknown +> : ^ ^^^^^^^^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>forwardRef( >( props: ComponentPropsWithoutRef, ref: Ref, ) => { return null; },) : >(props: PropsWithoutRef> & { ref?: Ref | undefined; }) => unknown +> : ^ ^^^^^^^^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>forwardRef : (component: (props: P, ref: Ref) => unknown) => (props: P & { ref?: Ref; }) => unknown +> : ^ ^^ ^^ ^^ ^^^^^ + + >( +>>( props: ComponentPropsWithoutRef, ref: Ref, ) => { return null; } : >(props: ComponentPropsWithoutRef, ref: Ref) => null +> : ^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^^^^^^^^ + + props: ComponentPropsWithoutRef, +>props : PropsWithoutRef> +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + ref: Ref, +>ref : Ref +> : ^^^^^^^^^^^^^^^^ + + ) => { + return null; + }, +); + +type Test = T extends { component?: infer Component } +>Test : Test +> : ^^^^^^^ +>component : Component | undefined +> : ^^^^^^^^^^^^^^^^^^^^^ + + ? Component extends FunctionComponent + ? ComponentProps + : never + : never; + +// the first one here has a chance to pollute the cache +type Result1 = ComponentProps; +>Result1 : Omit & { ref?: Ref | undefined; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>ComponentWithForwardRef : >(props: PropsWithoutRef> & { ref?: Ref | undefined; }) => unknown +> : ^ ^^^^^^^^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +// that could be incorrectly reused by this one +type Result2 = Test<{ component: typeof ComponentWithForwardRef }>; // no `T` leak +>Result2 : Omit & { ref?: Ref | undefined; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>component : >(props: PropsWithoutRef> & { ref?: Ref | undefined; }) => unknown +> : ^ ^^^^^^^^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>ComponentWithForwardRef : >(props: PropsWithoutRef> & { ref?: Ref | undefined; }) => unknown +> : ^ ^^^^^^^^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +// same as ComponentWithForwardRef above but using a resolved signature instead of a direct inferred result of `forwardRef` +declare const ComponentWithForwardRef2: >( +>ComponentWithForwardRef2 : >(props: PropsWithoutRef> & { className?: string; as?: T | undefined; } & { ref?: Ref | undefined; }) => unknown +> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ + + props: PropsWithoutRef> & { +>props : PropsWithoutRef> & { className?: string; as?: T | undefined; } & { ref?: Ref | undefined; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^ ^^^^^^^^^^^^^^ ^^^ + + className?: string; +>className : string | undefined +> : ^^^^^^^^^^^^^^^^^^ + + as?: T | undefined; +>as : T | undefined +> : ^^^^^^^^^^^^^ + + } & { + ref?: Ref | undefined; +>ref : Ref | undefined +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + }, +) => unknown; + +type Result3 = ComponentProps; +>Result3 : Omit & { className?: string; as?: FunctionComponent | undefined; } & { ref?: Ref | undefined; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^ +>ComponentWithForwardRef2 : >(props: PropsWithoutRef> & { className?: string; as?: T | undefined; } & { ref?: Ref | undefined; }) => unknown +> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ + +type Result4 = Test<{ component: typeof ComponentWithForwardRef2 }>; +>Result4 : Omit & { className?: string; as?: FunctionComponent | undefined; } & { ref?: Ref | undefined; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^ +>component : >(props: PropsWithoutRef> & { className?: string; as?: T | undefined; } & { ref?: Ref | undefined; }) => unknown +> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ +>ComponentWithForwardRef2 : >(props: PropsWithoutRef> & { className?: string; as?: T | undefined; } & { ref?: Ref | undefined; }) => unknown +> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ + diff --git a/tests/baselines/reference/genericCallInferenceWithGenericLocalFunction.symbols b/tests/baselines/reference/genericCallInferenceWithGenericLocalFunction.symbols index dec6af6bac2c5..9dd6d91bb1f7d 100644 --- a/tests/baselines/reference/genericCallInferenceWithGenericLocalFunction.symbols +++ b/tests/baselines/reference/genericCallInferenceWithGenericLocalFunction.symbols @@ -42,3 +42,60 @@ const added2 = addP2({ bar: 2 }); >addP2 : Symbol(addP2, Decl(genericCallInferenceWithGenericLocalFunction.ts, 9, 5)) >bar : Symbol(bar, Decl(genericCallInferenceWithGenericLocalFunction.ts, 10, 22)) +function withP3

(p: P) { +>withP3 : Symbol(withP3, Decl(genericCallInferenceWithGenericLocalFunction.ts, 10, 33)) +>P : Symbol(P, Decl(genericCallInferenceWithGenericLocalFunction.ts, 12, 16)) +>p : Symbol(p, Decl(genericCallInferenceWithGenericLocalFunction.ts, 12, 19)) +>P : Symbol(P, Decl(genericCallInferenceWithGenericLocalFunction.ts, 12, 16)) + + const m = +>m : Symbol(m, Decl(genericCallInferenceWithGenericLocalFunction.ts, 13, 7)) + + (from: I) => +>I : Symbol(I, Decl(genericCallInferenceWithGenericLocalFunction.ts, 14, 5)) +>from : Symbol(from, Decl(genericCallInferenceWithGenericLocalFunction.ts, 14, 9)) +>I : Symbol(I, Decl(genericCallInferenceWithGenericLocalFunction.ts, 14, 5)) + + (from2: I2) => ({ ...from, ...from2, ...p }); +>I2 : Symbol(I2, Decl(genericCallInferenceWithGenericLocalFunction.ts, 15, 5)) +>from2 : Symbol(from2, Decl(genericCallInferenceWithGenericLocalFunction.ts, 15, 10)) +>I2 : Symbol(I2, Decl(genericCallInferenceWithGenericLocalFunction.ts, 15, 5)) +>from : Symbol(from, Decl(genericCallInferenceWithGenericLocalFunction.ts, 14, 9)) +>from2 : Symbol(from2, Decl(genericCallInferenceWithGenericLocalFunction.ts, 15, 10)) +>p : Symbol(p, Decl(genericCallInferenceWithGenericLocalFunction.ts, 12, 19)) + + return createTransform(m); +>createTransform : Symbol(createTransform, Decl(genericCallInferenceWithGenericLocalFunction.ts, 2, 5)) +>m : Symbol(m, Decl(genericCallInferenceWithGenericLocalFunction.ts, 13, 7)) +} + +const addP3 = withP3({ a: 1 }); +>addP3 : Symbol(addP3, Decl(genericCallInferenceWithGenericLocalFunction.ts, 19, 5)) +>withP3 : Symbol(withP3, Decl(genericCallInferenceWithGenericLocalFunction.ts, 10, 33)) +>a : Symbol(a, Decl(genericCallInferenceWithGenericLocalFunction.ts, 19, 22)) + +const addedSome3 = addP3({ b: '' }); +>addedSome3 : Symbol(addedSome3, Decl(genericCallInferenceWithGenericLocalFunction.ts, 20, 5)) +>addP3 : Symbol(addP3, Decl(genericCallInferenceWithGenericLocalFunction.ts, 19, 5)) +>b : Symbol(b, Decl(genericCallInferenceWithGenericLocalFunction.ts, 20, 26)) + +const added3 = addedSome3({ c: true }); +>added3 : Symbol(added3, Decl(genericCallInferenceWithGenericLocalFunction.ts, 21, 5)) +>addedSome3 : Symbol(addedSome3, Decl(genericCallInferenceWithGenericLocalFunction.ts, 20, 5)) +>c : Symbol(c, Decl(genericCallInferenceWithGenericLocalFunction.ts, 21, 27)) + +const addP3_other = withP3({ foo: 'bar' }); +>addP3_other : Symbol(addP3_other, Decl(genericCallInferenceWithGenericLocalFunction.ts, 23, 5)) +>withP3 : Symbol(withP3, Decl(genericCallInferenceWithGenericLocalFunction.ts, 10, 33)) +>foo : Symbol(foo, Decl(genericCallInferenceWithGenericLocalFunction.ts, 23, 28)) + +const addedSome3_other = addP3_other({ qwerty: 123 }); +>addedSome3_other : Symbol(addedSome3_other, Decl(genericCallInferenceWithGenericLocalFunction.ts, 24, 5)) +>addP3_other : Symbol(addP3_other, Decl(genericCallInferenceWithGenericLocalFunction.ts, 23, 5)) +>qwerty : Symbol(qwerty, Decl(genericCallInferenceWithGenericLocalFunction.ts, 24, 38)) + +const added3_other = addedSome3_other({ bazinga: true }); +>added3_other : Symbol(added3_other, Decl(genericCallInferenceWithGenericLocalFunction.ts, 25, 5)) +>addedSome3_other : Symbol(addedSome3_other, Decl(genericCallInferenceWithGenericLocalFunction.ts, 24, 5)) +>bazinga : Symbol(bazinga, Decl(genericCallInferenceWithGenericLocalFunction.ts, 25, 39)) + diff --git a/tests/baselines/reference/genericCallInferenceWithGenericLocalFunction.types b/tests/baselines/reference/genericCallInferenceWithGenericLocalFunction.types index a49703b695d51..fb8c689e05f27 100644 --- a/tests/baselines/reference/genericCallInferenceWithGenericLocalFunction.types +++ b/tests/baselines/reference/genericCallInferenceWithGenericLocalFunction.types @@ -74,3 +74,128 @@ const added2 = addP2({ bar: 2 }); >2 : 2 > : ^ +function withP3

(p: P) { +>withP3 :

(p: P) => (from: I) => (from2: I2) => I & I2 & P +> : ^ ^^ ^^ ^^^^^^ ^^ ^^^^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^ +>p : P +> : ^ + + const m = +>m : (from: I) => (from2: I2) => I & I2 & P +> : ^ ^^ ^^ ^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^ + + (from: I) => +>(from: I) => (from2: I2) => ({ ...from, ...from2, ...p }) : (from: I) => (from2: I2) => I & I2 & P +> : ^ ^^ ^^ ^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^ +>from : I +> : ^ + + (from2: I2) => ({ ...from, ...from2, ...p }); +>(from2: I2) => ({ ...from, ...from2, ...p }) : (from2: I2) => I & I2 & P +> : ^ ^^ ^^ ^^^^^^^^^^^^^^^ +>from2 : I2 +> : ^^ +>({ ...from, ...from2, ...p }) : I & I2 & P +> : ^^^^^^^^^^ +>{ ...from, ...from2, ...p } : I & I2 & P +> : ^^^^^^^^^^ +>from : I +> : ^ +>from2 : I2 +> : ^^ +>p : P +> : ^ + + return createTransform(m); +>createTransform(m) : (from: I) => (from2: I2) => I & I2 & P +> : ^ ^^ ^^^^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^ +>createTransform : (tr: (from: I) => O) => (from: I) => O +> : ^ ^^ ^^ ^^ ^^^^^^ ^^ ^^^^^ +>m : (from: I) => (from2: I2) => I & I2 & P +> : ^ ^^ ^^ ^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^ +} + +const addP3 = withP3({ a: 1 }); +>addP3 : (from: I) => (from2: I2) => I & I2 & { a: number; } +> : ^ ^^ ^^^^^^^^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>withP3({ a: 1 }) : (from: I) => (from2: I2) => I & I2 & { a: number; } +> : ^ ^^ ^^^^^^^^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>withP3 :

(p: P) => (from: I) => (from2: I2) => I & I2 & P +> : ^ ^^ ^^ ^^^^^^ ^^ ^^^^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^ +>{ a: 1 } : { a: number; } +> : ^^^^^^^^^^^^^^ +>a : number +> : ^^^^^^ +>1 : 1 +> : ^ + +const addedSome3 = addP3({ b: '' }); +>addedSome3 : (from2: I2) => { b: string; } & I2 & { a: number; } +> : ^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>addP3({ b: '' }) : (from2: I2) => { b: string; } & I2 & { a: number; } +> : ^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>addP3 : (from: I) => (from2: I2) => I & I2 & { a: number; } +> : ^ ^^ ^^^^^^^^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>{ b: '' } : { b: string; } +> : ^^^^^^^^^^^^^^ +>b : string +> : ^^^^^^ +>'' : "" +> : ^^ + +const added3 = addedSome3({ c: true }); +>added3 : { b: string; } & { c: boolean; } & { a: number; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>addedSome3({ c: true }) : { b: string; } & { c: boolean; } & { a: number; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>addedSome3 : (from2: I2) => { b: string; } & I2 & { a: number; } +> : ^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>{ c: true } : { c: true; } +> : ^^^^^^^^^^^^ +>c : true +> : ^^^^ +>true : true +> : ^^^^ + +const addP3_other = withP3({ foo: 'bar' }); +>addP3_other : (from: I) => (from2: I2) => I & I2 & { foo: string; } +> : ^ ^^ ^^^^^^^^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>withP3({ foo: 'bar' }) : (from: I) => (from2: I2) => I & I2 & { foo: string; } +> : ^ ^^ ^^^^^^^^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>withP3 :

(p: P) => (from: I) => (from2: I2) => I & I2 & P +> : ^ ^^ ^^ ^^^^^^ ^^ ^^^^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^ +>{ foo: 'bar' } : { foo: string; } +> : ^^^^^^^^^^^^^^^^ +>foo : string +> : ^^^^^^ +>'bar' : "bar" +> : ^^^^^ + +const addedSome3_other = addP3_other({ qwerty: 123 }); +>addedSome3_other : (from2: I2) => { qwerty: number; } & I2 & { foo: string; } +> : ^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>addP3_other({ qwerty: 123 }) : (from2: I2) => { qwerty: number; } & I2 & { foo: string; } +> : ^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>addP3_other : (from: I) => (from2: I2) => I & I2 & { foo: string; } +> : ^ ^^ ^^^^^^^^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>{ qwerty: 123 } : { qwerty: number; } +> : ^^^^^^^^^^^^^^^^^^^ +>qwerty : number +> : ^^^^^^ +>123 : 123 +> : ^^^ + +const added3_other = addedSome3_other({ bazinga: true }); +>added3_other : { qwerty: number; } & { bazinga: boolean; } & { foo: string; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>addedSome3_other({ bazinga: true }) : { qwerty: number; } & { bazinga: boolean; } & { foo: string; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>addedSome3_other : (from2: I2) => { qwerty: number; } & I2 & { foo: string; } +> : ^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>{ bazinga: true } : { bazinga: true; } +> : ^^^^^^^^^^^^^^^^^^ +>bazinga : true +> : ^^^^ +>true : true +> : ^^^^ + diff --git a/tests/cases/compiler/genericCallInferenceInConditionalTypes1.ts b/tests/cases/compiler/genericCallInferenceInConditionalTypes1.ts new file mode 100644 index 0000000000000..ff95031cbf728 --- /dev/null +++ b/tests/cases/compiler/genericCallInferenceInConditionalTypes1.ts @@ -0,0 +1,59 @@ +// @strict: true +// @noEmit: true + +// https://github.com/microsoft/TypeScript/issues/59937 + +type Ref = { + current: T; +}; + +type FunctionComponent

= (props: P) => unknown; + +type ComponentProps> = + T extends FunctionComponent ? P : {}; + +type PropsWithoutRef

= P extends any + ? "ref" extends keyof P + ? Omit + : P + : P; + +type ComponentPropsWithoutRef> = + PropsWithoutRef>; + +declare function forwardRef( + component: (props: P, ref: Ref) => unknown, +): (props: P & { ref?: Ref }) => unknown; + +const ComponentWithForwardRef = forwardRef( + >( + props: ComponentPropsWithoutRef, + ref: Ref, + ) => { + return null; + }, +); + +type Test = T extends { component?: infer Component } + ? Component extends FunctionComponent + ? ComponentProps + : never + : never; + +// the first one here has a chance to pollute the cache +type Result1 = ComponentProps; +// that could be incorrectly reused by this one +type Result2 = Test<{ component: typeof ComponentWithForwardRef }>; // no `T` leak + +// same as ComponentWithForwardRef above but using a resolved signature instead of a direct inferred result of `forwardRef` +declare const ComponentWithForwardRef2: >( + props: PropsWithoutRef> & { + className?: string; + as?: T | undefined; + } & { + ref?: Ref | undefined; + }, +) => unknown; + +type Result3 = ComponentProps; +type Result4 = Test<{ component: typeof ComponentWithForwardRef2 }>; diff --git a/tests/cases/compiler/genericCallInferenceWithGenericLocalFunction.ts b/tests/cases/compiler/genericCallInferenceWithGenericLocalFunction.ts index 1aff11c5b3507..57c14a76ba6f6 100644 --- a/tests/cases/compiler/genericCallInferenceWithGenericLocalFunction.ts +++ b/tests/cases/compiler/genericCallInferenceWithGenericLocalFunction.ts @@ -12,3 +12,18 @@ function withP2

(p: P) { const addP2 = withP2({ foo: 1 }); const added2 = addP2({ bar: 2 }); + +function withP3

(p: P) { + const m = + (from: I) => + (from2: I2) => ({ ...from, ...from2, ...p }); + return createTransform(m); +} + +const addP3 = withP3({ a: 1 }); +const addedSome3 = addP3({ b: '' }); +const added3 = addedSome3({ c: true }); + +const addP3_other = withP3({ foo: 'bar' }); +const addedSome3_other = addP3_other({ qwerty: 123 }); +const added3_other = addedSome3_other({ bazinga: true });