diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 84b111555df7e..4afe02a324d17 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -25695,10 +25695,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { inferToMultipleTypes(source, (target as UnionOrIntersectionType).types, target.flags); } else if (source.flags & TypeFlags.Union) { - // Source is a union or intersection type, infer from each constituent type - const sourceTypes = (source as UnionOrIntersectionType).types; - for (const sourceType of sourceTypes) { - inferFromTypes(sourceType, target); + const singleSignature = getSingleCallOrConstructSignature(source); + if (singleSignature) { + inferFromTypes(getOrCreateTypeFromSignature(singleSignature), target); + } + else { + // Source is a union type, infer from each constituent type + const sourceTypes = (source as UnionType).types; + for (const sourceType of sourceTypes) { + inferFromTypes(sourceType, target); + } } } else if (target.flags & TypeFlags.TemplateLiteral) { @@ -33946,8 +33952,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getSingleSignature(type: Type, kind: SignatureKind, allowMembers: boolean): Signature | undefined { - if (type.flags & TypeFlags.Object) { - const resolved = resolveStructuredTypeMembers(type as ObjectType); + if (type.flags & TypeFlags.StructuredType) { + const resolved = resolveStructuredTypeMembers(type as StructuredType); if (allowMembers || resolved.properties.length === 0 && resolved.indexInfos.length === 0) { if (kind === SignatureKind.Call && resolved.callSignatures.length === 1 && resolved.constructSignatures.length === 0) { return resolved.callSignatures[0]; diff --git a/tests/baselines/reference/inferenceFromUnionCombinedSingleSignature1.symbols b/tests/baselines/reference/inferenceFromUnionCombinedSingleSignature1.symbols new file mode 100644 index 0000000000000..e34449bcf8cb2 --- /dev/null +++ b/tests/baselines/reference/inferenceFromUnionCombinedSingleSignature1.symbols @@ -0,0 +1,29 @@ +//// [tests/cases/compiler/inferenceFromUnionCombinedSingleSignature1.ts] //// + +=== inferenceFromUnionCombinedSingleSignature1.ts === +// https://github.com/microsoft/TypeScript/issues/58468 + +declare const fn: (() => void) | ((a: number) => void); +>fn : Symbol(fn, Decl(inferenceFromUnionCombinedSingleSignature1.ts, 2, 13)) +>a : Symbol(a, Decl(inferenceFromUnionCombinedSingleSignature1.ts, 2, 35)) + +declare const x: number; +>x : Symbol(x, Decl(inferenceFromUnionCombinedSingleSignature1.ts, 4, 13)) + +declare const y: any; +>y : Symbol(y, Decl(inferenceFromUnionCombinedSingleSignature1.ts, 5, 13)) + +fn.call(null, x); +>fn.call : Symbol(CallableFunction.call, Decl(lib.es5.d.ts, --, --)) +>fn : Symbol(fn, Decl(inferenceFromUnionCombinedSingleSignature1.ts, 2, 13)) +>call : Symbol(CallableFunction.call, Decl(lib.es5.d.ts, --, --)) +>x : Symbol(x, Decl(inferenceFromUnionCombinedSingleSignature1.ts, 4, 13)) + +fn.call(null, y); +>fn.call : Symbol(CallableFunction.call, Decl(lib.es5.d.ts, --, --)) +>fn : Symbol(fn, Decl(inferenceFromUnionCombinedSingleSignature1.ts, 2, 13)) +>call : Symbol(CallableFunction.call, Decl(lib.es5.d.ts, --, --)) +>y : Symbol(y, Decl(inferenceFromUnionCombinedSingleSignature1.ts, 5, 13)) + +export {}; + diff --git a/tests/baselines/reference/inferenceFromUnionCombinedSingleSignature1.types b/tests/baselines/reference/inferenceFromUnionCombinedSingleSignature1.types new file mode 100644 index 0000000000000..55a8783f88d1f --- /dev/null +++ b/tests/baselines/reference/inferenceFromUnionCombinedSingleSignature1.types @@ -0,0 +1,43 @@ +//// [tests/cases/compiler/inferenceFromUnionCombinedSingleSignature1.ts] //// + +=== inferenceFromUnionCombinedSingleSignature1.ts === +// https://github.com/microsoft/TypeScript/issues/58468 + +declare const fn: (() => void) | ((a: number) => void); +>fn : (() => void) | ((a: number) => void) +> : ^^^^^^^ ^^^^^^ ^^ ^^^^^ ^ +>a : number +> : ^^^^^^ + +declare const x: number; +>x : number +> : ^^^^^^ + +declare const y: any; +>y : any + +fn.call(null, x); +>fn.call(null, x) : void +> : ^^^^ +>fn.call : (this: (this: T, ...args: A) => R, thisArg: T, ...args: A) => R +> : ^ ^^ ^^^^^^^^^^^^^^^^ ^^ ^^ ^^ ^^ ^^^^^ ^^ ^^^^^^ +>fn : (() => void) | ((a: number) => void) +> : ^^^^^^^^^^^^^^^^^ ^^ ^^^^^^^^^^ +>call : (this: (this: T, ...args: A) => R, thisArg: T, ...args: A) => R +> : ^ ^^ ^^^^^^^^^^^^^^^^ ^^ ^^ ^^ ^^ ^^^^^ ^^ ^^^^^^ +>x : number +> : ^^^^^^ + +fn.call(null, y); +>fn.call(null, y) : void +> : ^^^^ +>fn.call : (this: (this: T, ...args: A) => R, thisArg: T, ...args: A) => R +> : ^ ^^ ^^^^^^^^^^^^^^^^ ^^ ^^ ^^ ^^ ^^^^^ ^^ ^^^^^^ +>fn : (() => void) | ((a: number) => void) +> : ^^^^^^^^^^^^^^^^^ ^^ ^^^^^^^^^^ +>call : (this: (this: T, ...args: A) => R, thisArg: T, ...args: A) => R +> : ^ ^^ ^^^^^^^^^^^^^^^^ ^^ ^^ ^^ ^^ ^^^^^ ^^ ^^^^^^ +>y : any + +export {}; + diff --git a/tests/baselines/reference/jsDeclarationsGetterSetter.js b/tests/baselines/reference/jsDeclarationsGetterSetter.js index 90a1a35f8a873..994dd0e63ebb5 100644 --- a/tests/baselines/reference/jsDeclarationsGetterSetter.js +++ b/tests/baselines/reference/jsDeclarationsGetterSetter.js @@ -280,5 +280,5 @@ export class L { set x(value: any); } export class M { - set x(value: any); + set x(value: boolean); } diff --git a/tests/baselines/reference/neverIntersectionNotCallable.types b/tests/baselines/reference/neverIntersectionNotCallable.types index fab7840e6b7ea..e2baf29c4c67b 100644 --- a/tests/baselines/reference/neverIntersectionNotCallable.types +++ b/tests/baselines/reference/neverIntersectionNotCallable.types @@ -12,8 +12,8 @@ declare const f: { (x: string): number, a: "" } & { a: number } > : ^^^^^^ f() ->f() : any -> : ^^^ +>f() : number +> : ^^^^^^ >f : never > : ^^^^^ diff --git a/tests/cases/compiler/inferenceFromUnionCombinedSingleSignature1.ts b/tests/cases/compiler/inferenceFromUnionCombinedSingleSignature1.ts new file mode 100644 index 0000000000000..ab13ce7c1d909 --- /dev/null +++ b/tests/cases/compiler/inferenceFromUnionCombinedSingleSignature1.ts @@ -0,0 +1,14 @@ +// @strict: true +// @noEmit: true + +// https://github.com/microsoft/TypeScript/issues/58468 + +declare const fn: (() => void) | ((a: number) => void); + +declare const x: number; +declare const y: any; + +fn.call(null, x); +fn.call(null, y); + +export {};