diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 3d4f288f1293b..0599d2fda8925 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -38973,7 +38973,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // potentially add inferred type parameters to the outer function return type. const returnType = context.signature && getReturnTypeOfSignature(context.signature); const returnSignature = returnType && getSingleCallOrConstructSignature(returnType); - if (returnSignature && !returnSignature.typeParameters && !every(context.inferences, hasInferenceCandidates)) { + if (returnSignature && !returnSignature.typeParameters && !every(context.inferences, info => hasInferenceCandidates(info) && info.priority === InferencePriority.None)) { // Instantiate the signature with its own type parameters as type arguments, possibly // renaming the type parameters to ensure they have unique names. const uniqueTypeParameters = getUniqueTypeParameters(context, signature.typeParameters); @@ -38993,8 +38993,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // If the type parameters for which we produced candidates do not have any inferences yet, // we adopt the new inference candidates and add the type parameters of the expression type // to the set of inferred type parameters for the outer function return type. - if (!hasOverlappingInferences(context.inferences, inferences)) { - mergeInferences(context.inferences, inferences); + const merged = tryInferencesMerge(context.inferences, inferences); + if (merged) { context.inferredTypeParameters = concatenate(context.inferredTypeParameters, uniqueTypeParameters); return getOrCreateTypeFromSignature(instantiatedSignature); } @@ -39034,12 +39034,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return false; } - function mergeInferences(target: InferenceInfo[], source: InferenceInfo[]) { + function tryInferencesMerge(target: InferenceInfo[], source: InferenceInfo[]) { + let merged = false; + + const areOverlapping = hasOverlappingInferences(target, source); + for (let i = 0; i < target.length; i++) { - if (!hasInferenceCandidates(target[i]) && hasInferenceCandidates(source[i])) { - target[i] = source[i]; + if (areOverlapping ? hasInferenceCandidates(source[i]) && hasInferenceCandidates(target[i]) && source[i].priority! < (target[i].priority! & ~InferencePriority.ReturnType) : hasInferenceCandidates(source[i])) { + const clonedInferenceInfo = cloneInferenceInfo(source[i]); + clonedInferenceInfo.priority = InferencePriority.None; + target[i] = clonedInferenceInfo; + merged = true; } } + return merged; } function getUniqueTypeParameters(context: InferenceContext, typeParameters: readonly TypeParameter[]): readonly TypeParameter[] { diff --git a/tests/baselines/reference/genericFunctionInference3.symbols b/tests/baselines/reference/genericFunctionInference3.symbols new file mode 100644 index 0000000000000..114a5ff578fd0 --- /dev/null +++ b/tests/baselines/reference/genericFunctionInference3.symbols @@ -0,0 +1,60 @@ +//// [tests/cases/compiler/genericFunctionInference3.ts] //// + +=== genericFunctionInference3.ts === +// https://github.com/microsoft/TypeScript/issues/56931 + +declare function defineComponent>( +>defineComponent : Symbol(defineComponent, Decl(genericFunctionInference3.ts, 0, 0)) +>Props : Symbol(Props, Decl(genericFunctionInference3.ts, 2, 33)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) + + setup: (props: Props) => void, +>setup : Symbol(setup, Decl(genericFunctionInference3.ts, 2, 68)) +>props : Symbol(props, Decl(genericFunctionInference3.ts, 3, 10)) +>Props : Symbol(Props, Decl(genericFunctionInference3.ts, 2, 33)) + + options?: { +>options : Symbol(options, Decl(genericFunctionInference3.ts, 3, 32)) + + props?: (keyof Props)[]; +>props : Symbol(props, Decl(genericFunctionInference3.ts, 4, 13)) +>Props : Symbol(Props, Decl(genericFunctionInference3.ts, 2, 33)) + + }, +): (props: Props) => unknown; +>props : Symbol(props, Decl(genericFunctionInference3.ts, 7, 4)) +>Props : Symbol(Props, Decl(genericFunctionInference3.ts, 2, 33)) + +const res1 = defineComponent( +>res1 : Symbol(res1, Decl(genericFunctionInference3.ts, 9, 5)) +>defineComponent : Symbol(defineComponent, Decl(genericFunctionInference3.ts, 0, 0)) + + (_props: { msg: T }) => { +>T : Symbol(T, Decl(genericFunctionInference3.ts, 10, 3)) +>_props : Symbol(_props, Decl(genericFunctionInference3.ts, 10, 21)) +>msg : Symbol(msg, Decl(genericFunctionInference3.ts, 10, 30)) +>T : Symbol(T, Decl(genericFunctionInference3.ts, 10, 3)) + + return () => {}; + } +); + +const res2 = defineComponent( +>res2 : Symbol(res2, Decl(genericFunctionInference3.ts, 15, 5)) +>defineComponent : Symbol(defineComponent, Decl(genericFunctionInference3.ts, 0, 0)) + + (_props: { msg: T }) => { +>T : Symbol(T, Decl(genericFunctionInference3.ts, 16, 3)) +>_props : Symbol(_props, Decl(genericFunctionInference3.ts, 16, 21)) +>msg : Symbol(msg, Decl(genericFunctionInference3.ts, 16, 30)) +>T : Symbol(T, Decl(genericFunctionInference3.ts, 16, 3)) + + return () => {}; + }, + { + props: ["msg"], +>props : Symbol(props, Decl(genericFunctionInference3.ts, 19, 3)) + + }, +); + diff --git a/tests/baselines/reference/genericFunctionInference3.types b/tests/baselines/reference/genericFunctionInference3.types new file mode 100644 index 0000000000000..697cb03213884 --- /dev/null +++ b/tests/baselines/reference/genericFunctionInference3.types @@ -0,0 +1,62 @@ +//// [tests/cases/compiler/genericFunctionInference3.ts] //// + +=== genericFunctionInference3.ts === +// https://github.com/microsoft/TypeScript/issues/56931 + +declare function defineComponent>( +>defineComponent : >(setup: (props: Props) => void, options?: { props?: (keyof Props)[];}) => (props: Props) => unknown + + setup: (props: Props) => void, +>setup : (props: Props) => void +>props : Props + + options?: { +>options : { props?: (keyof Props)[] | undefined; } | undefined + + props?: (keyof Props)[]; +>props : (keyof Props)[] | undefined + + }, +): (props: Props) => unknown; +>props : Props + +const res1 = defineComponent( +>res1 : (props: { msg: T; }) => unknown +>defineComponent( (_props: { msg: T }) => { return () => {}; }) : (props: { msg: T; }) => unknown +>defineComponent : >(setup: (props: Props) => void, options?: { props?: (keyof Props)[] | undefined; } | undefined) => (props: Props) => unknown + + (_props: { msg: T }) => { +>(_props: { msg: T }) => { return () => {}; } : (_props: { msg: T;}) => () => void +>_props : { msg: T; } +>msg : T + + return () => {}; +>() => {} : () => void + } +); + +const res2 = defineComponent( +>res2 : (props: { msg: T; }) => unknown +>defineComponent( (_props: { msg: T }) => { return () => {}; }, { props: ["msg"], },) : (props: { msg: T; }) => unknown +>defineComponent : >(setup: (props: Props) => void, options?: { props?: (keyof Props)[] | undefined; } | undefined) => (props: Props) => unknown + + (_props: { msg: T }) => { +>(_props: { msg: T }) => { return () => {}; } : (_props: { msg: T;}) => () => void +>_props : { msg: T; } +>msg : T + + return () => {}; +>() => {} : () => void + + }, + { +>{ props: ["msg"], } : { props: "msg"[]; } + + props: ["msg"], +>props : "msg"[] +>["msg"] : "msg"[] +>"msg" : "msg" + + }, +); + diff --git a/tests/cases/compiler/genericFunctionInference3.ts b/tests/cases/compiler/genericFunctionInference3.ts new file mode 100644 index 0000000000000..63d441e5e6627 --- /dev/null +++ b/tests/cases/compiler/genericFunctionInference3.ts @@ -0,0 +1,26 @@ +// @strict: true +// @noEmit: true + +// https://github.com/microsoft/TypeScript/issues/56931 + +declare function defineComponent>( + setup: (props: Props) => void, + options?: { + props?: (keyof Props)[]; + }, +): (props: Props) => unknown; + +const res1 = defineComponent( + (_props: { msg: T }) => { + return () => {}; + } +); + +const res2 = defineComponent( + (_props: { msg: T }) => { + return () => {}; + }, + { + props: ["msg"], + }, +);