-
Notifications
You must be signed in to change notification settings - Fork 12.9k
Fix Callback argument type not inferred for union of interfaces #59309 #59672
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
25b5914
effe3a0
ed2bfa4
2e530af
ac64f64
6eaf5e3
f69d6e1
8b0b855
8a3b095
dcb8f5d
4fd6bbd
381e4e0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -32422,29 +32422,28 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { | |||||
if (!(type.flags & TypeFlags.Union)) { | ||||||
return getContextualCallSignature(type, node); | ||||||
} | ||||||
let signatureList: Signature[] | undefined; | ||||||
const types = (type as UnionType).types; | ||||||
for (const current of types) { | ||||||
const signature = getContextualCallSignature(current, node); | ||||||
if (signature) { | ||||||
if (!signatureList) { | ||||||
// This signature will contribute to contextual union signature | ||||||
signatureList = [signature]; | ||||||
} | ||||||
else if (!compareSignaturesIdentical(signatureList[0], signature, /*partialMatch*/ false, /*ignoreThisTypes*/ true, /*ignoreReturnTypes*/ true, compareTypesIdentical)) { | ||||||
// Signatures aren't identical, do not use | ||||||
return undefined; | ||||||
} | ||||||
else { | ||||||
// Use this signature for contextual union signature | ||||||
signatureList.push(signature); | ||||||
} | ||||||
|
||||||
let signatures = mapDefined((type as UnionType).types, t => getContextualCallSignature(t, node)); | ||||||
const functionFlags = getFunctionFlags(node); | ||||||
if (functionFlags & FunctionFlags.Generator) { | ||||||
MichalMarsalek marked this conversation as resolved.
Show resolved
Hide resolved
MichalMarsalek marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
signatures = filter(signatures, s => checkGeneratorInstantiationAssignabilityToReturnType(getReturnTypeOfSignature(s), functionFlags, /*errorNode*/ undefined)); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You need to account for rest parameters here so it would be more appropriate to use ((a: string, b?: string) => void) | ((a: string, ...rest: string[]) => void) Both of those signatures have the same parameter count but perhaps you'd like to specifically sort one of them as the first one. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thank you. I think that actually what I need is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure if it will make any difference but to exercise even more funky test cases you could add test cases with signatures of this shape: ((a: string, ...rest: [string, number?] | [number, boolean?]) => void) | ((a: string, ...rest: [string, number] | [number, boolean]) => void) Note that I didn't think through what types you should use in those rest parameters, just that they can be unions of tuples and that one of the signatures might have some of the elements there required and some might have them optional etc. |
||||||
} | ||||||
else if (functionFlags & FunctionFlags.Async) { | ||||||
signatures = filter(signatures, s => !!getAwaitedTypeOfPromise(getReturnTypeOfSignature(s))); | ||||||
} | ||||||
signatures.sort((s1, s2) => getMinArgumentCount(s1) - getMinArgumentCount(s2)); | ||||||
if (!signatures.length) { | ||||||
return; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you are loosening here how parameter types are meant to be compared I'd probably expect here:
Suggested change
Unless there is already a reason why the subtype relationship was used here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not really sure when each relation should be used. I used There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||||
} | ||||||
|
||||||
for (let i = 1; i < signatures.length; i++) { | ||||||
if (!compareSignaturesIdentical(signatures[0], signatures[i], /*partialMatch*/ true, /*ignoreThisTypes*/ true, /*ignoreReturnTypes*/ true, compareTypesSubtypeOf)) { | ||||||
// Signatures aren't identical, do not use | ||||||
return undefined; | ||||||
} | ||||||
} | ||||||
// Result is union of signatures collected (return type is union of return types of this signature set) | ||||||
if (signatureList) { | ||||||
return signatureList.length === 1 ? signatureList[0] : createUnionSignature(signatureList[0], signatureList); | ||||||
} | ||||||
return signatures.length === 1 ? signatures[0] : createUnionSignature(signatures[0], signatures); | ||||||
} | ||||||
|
||||||
function checkGrammarRegularExpressionLiteral(node: RegularExpressionLiteral) { | ||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,229 @@ | ||
//// [tests/cases/compiler/contextualSignatureWithExtraParameters.ts] //// | ||
|
||
=== contextualSignatureWithExtraParameters.ts === | ||
// https://github.com/microsoft/TypeScript/issues/59309 | ||
function f1( | ||
>f1 : Symbol(f1, Decl(contextualSignatureWithExtraParameters.ts, 0, 0)) | ||
|
||
cb: ((item: number) => void) | ((item: number, extra: string) => void), | ||
>cb : Symbol(cb, Decl(contextualSignatureWithExtraParameters.ts, 1, 12)) | ||
>item : Symbol(item, Decl(contextualSignatureWithExtraParameters.ts, 2, 10)) | ||
>item : Symbol(item, Decl(contextualSignatureWithExtraParameters.ts, 2, 37)) | ||
>extra : Symbol(extra, Decl(contextualSignatureWithExtraParameters.ts, 2, 50)) | ||
|
||
) {} | ||
|
||
f1((item) => {}); | ||
>f1 : Symbol(f1, Decl(contextualSignatureWithExtraParameters.ts, 0, 0)) | ||
>item : Symbol(item, Decl(contextualSignatureWithExtraParameters.ts, 5, 4)) | ||
|
||
function f2<T>( | ||
>f2 : Symbol(f2, Decl(contextualSignatureWithExtraParameters.ts, 5, 17)) | ||
>T : Symbol(T, Decl(contextualSignatureWithExtraParameters.ts, 7, 12)) | ||
|
||
arr: T[], | ||
>arr : Symbol(arr, Decl(contextualSignatureWithExtraParameters.ts, 7, 15)) | ||
>T : Symbol(T, Decl(contextualSignatureWithExtraParameters.ts, 7, 12)) | ||
|
||
cb: ((item: T) => void) | ((item: T, extra: unknown) => void), | ||
>cb : Symbol(cb, Decl(contextualSignatureWithExtraParameters.ts, 8, 13)) | ||
>item : Symbol(item, Decl(contextualSignatureWithExtraParameters.ts, 9, 10)) | ||
>T : Symbol(T, Decl(contextualSignatureWithExtraParameters.ts, 7, 12)) | ||
>item : Symbol(item, Decl(contextualSignatureWithExtraParameters.ts, 9, 32)) | ||
>T : Symbol(T, Decl(contextualSignatureWithExtraParameters.ts, 7, 12)) | ||
>extra : Symbol(extra, Decl(contextualSignatureWithExtraParameters.ts, 9, 40)) | ||
|
||
) {} | ||
|
||
f2([1, 2, 3], (item) => {}); | ||
>f2 : Symbol(f2, Decl(contextualSignatureWithExtraParameters.ts, 5, 17)) | ||
>item : Symbol(item, Decl(contextualSignatureWithExtraParameters.ts, 12, 15)) | ||
|
||
export interface AsyncResultCallback<T, E = Error> { | ||
>AsyncResultCallback : Symbol(AsyncResultCallback, Decl(contextualSignatureWithExtraParameters.ts, 12, 28)) | ||
>T : Symbol(T, Decl(contextualSignatureWithExtraParameters.ts, 14, 37)) | ||
>E : Symbol(E, Decl(contextualSignatureWithExtraParameters.ts, 14, 39)) | ||
>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2022.error.d.ts, --, --)) | ||
|
||
(err?: E | null, result?: T): void; | ||
>err : Symbol(err, Decl(contextualSignatureWithExtraParameters.ts, 15, 5)) | ||
>E : Symbol(E, Decl(contextualSignatureWithExtraParameters.ts, 14, 39)) | ||
>result : Symbol(result, Decl(contextualSignatureWithExtraParameters.ts, 15, 20)) | ||
>T : Symbol(T, Decl(contextualSignatureWithExtraParameters.ts, 14, 37)) | ||
} | ||
|
||
export interface AsyncResultIterator<T, R, E = Error> { | ||
>AsyncResultIterator : Symbol(AsyncResultIterator, Decl(contextualSignatureWithExtraParameters.ts, 16, 1)) | ||
>T : Symbol(T, Decl(contextualSignatureWithExtraParameters.ts, 18, 37)) | ||
>R : Symbol(R, Decl(contextualSignatureWithExtraParameters.ts, 18, 39)) | ||
>E : Symbol(E, Decl(contextualSignatureWithExtraParameters.ts, 18, 42)) | ||
>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2022.error.d.ts, --, --)) | ||
|
||
(item: T, callback: AsyncResultCallback<R, E>): void; | ||
>item : Symbol(item, Decl(contextualSignatureWithExtraParameters.ts, 19, 5)) | ||
>T : Symbol(T, Decl(contextualSignatureWithExtraParameters.ts, 18, 37)) | ||
>callback : Symbol(callback, Decl(contextualSignatureWithExtraParameters.ts, 19, 13)) | ||
>AsyncResultCallback : Symbol(AsyncResultCallback, Decl(contextualSignatureWithExtraParameters.ts, 12, 28)) | ||
>R : Symbol(R, Decl(contextualSignatureWithExtraParameters.ts, 18, 39)) | ||
>E : Symbol(E, Decl(contextualSignatureWithExtraParameters.ts, 18, 42)) | ||
} | ||
export interface AsyncResultIteratorPromise<T, R> { | ||
>AsyncResultIteratorPromise : Symbol(AsyncResultIteratorPromise, Decl(contextualSignatureWithExtraParameters.ts, 20, 1)) | ||
>T : Symbol(T, Decl(contextualSignatureWithExtraParameters.ts, 21, 44)) | ||
>R : Symbol(R, Decl(contextualSignatureWithExtraParameters.ts, 21, 46)) | ||
|
||
(item: T): Promise<R>; | ||
>item : Symbol(item, Decl(contextualSignatureWithExtraParameters.ts, 22, 5)) | ||
>T : Symbol(T, Decl(contextualSignatureWithExtraParameters.ts, 21, 44)) | ||
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2018.promise.d.ts, --, --)) | ||
>R : Symbol(R, Decl(contextualSignatureWithExtraParameters.ts, 21, 46)) | ||
} | ||
|
||
declare function mapLimit<T, R, E = Error>( | ||
>mapLimit : Symbol(mapLimit, Decl(contextualSignatureWithExtraParameters.ts, 23, 1)) | ||
>T : Symbol(T, Decl(contextualSignatureWithExtraParameters.ts, 25, 26)) | ||
>R : Symbol(R, Decl(contextualSignatureWithExtraParameters.ts, 25, 28)) | ||
>E : Symbol(E, Decl(contextualSignatureWithExtraParameters.ts, 25, 31)) | ||
>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2022.error.d.ts, --, --)) | ||
|
||
arr: T[], | ||
>arr : Symbol(arr, Decl(contextualSignatureWithExtraParameters.ts, 25, 43)) | ||
>T : Symbol(T, Decl(contextualSignatureWithExtraParameters.ts, 25, 26)) | ||
|
||
limit: number, | ||
>limit : Symbol(limit, Decl(contextualSignatureWithExtraParameters.ts, 26, 13)) | ||
|
||
iterator: AsyncResultIteratorPromise<T, R> | AsyncResultIterator<T, R, E>, | ||
>iterator : Symbol(iterator, Decl(contextualSignatureWithExtraParameters.ts, 27, 18)) | ||
>AsyncResultIteratorPromise : Symbol(AsyncResultIteratorPromise, Decl(contextualSignatureWithExtraParameters.ts, 20, 1)) | ||
>T : Symbol(T, Decl(contextualSignatureWithExtraParameters.ts, 25, 26)) | ||
>R : Symbol(R, Decl(contextualSignatureWithExtraParameters.ts, 25, 28)) | ||
>AsyncResultIterator : Symbol(AsyncResultIterator, Decl(contextualSignatureWithExtraParameters.ts, 16, 1)) | ||
>T : Symbol(T, Decl(contextualSignatureWithExtraParameters.ts, 25, 26)) | ||
>R : Symbol(R, Decl(contextualSignatureWithExtraParameters.ts, 25, 28)) | ||
>E : Symbol(E, Decl(contextualSignatureWithExtraParameters.ts, 25, 31)) | ||
|
||
): Promise<R[]>; | ||
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2018.promise.d.ts, --, --)) | ||
>R : Symbol(R, Decl(contextualSignatureWithExtraParameters.ts, 25, 28)) | ||
|
||
mapLimit([1,2,3], 3, async (n) => { | ||
>mapLimit : Symbol(mapLimit, Decl(contextualSignatureWithExtraParameters.ts, 23, 1)) | ||
>n : Symbol(n, Decl(contextualSignatureWithExtraParameters.ts, 31, 28)) | ||
|
||
return n ** 2; | ||
>n : Symbol(n, Decl(contextualSignatureWithExtraParameters.ts, 31, 28)) | ||
|
||
}); | ||
|
||
function f3( | ||
>f3 : Symbol(f3, Decl(contextualSignatureWithExtraParameters.ts, 33, 3)) | ||
|
||
cb: ((a: string, b?: string) => void) | ((a: string, ...rest: string[]) => void) | ||
>cb : Symbol(cb, Decl(contextualSignatureWithExtraParameters.ts, 35, 12)) | ||
>a : Symbol(a, Decl(contextualSignatureWithExtraParameters.ts, 36, 10)) | ||
>b : Symbol(b, Decl(contextualSignatureWithExtraParameters.ts, 36, 20)) | ||
>a : Symbol(a, Decl(contextualSignatureWithExtraParameters.ts, 36, 46)) | ||
>rest : Symbol(rest, Decl(contextualSignatureWithExtraParameters.ts, 36, 56)) | ||
|
||
) {} | ||
|
||
f3((a) => {}); | ||
>f3 : Symbol(f3, Decl(contextualSignatureWithExtraParameters.ts, 33, 3)) | ||
>a : Symbol(a, Decl(contextualSignatureWithExtraParameters.ts, 39, 4)) | ||
|
||
f3((a, b) => {}); | ||
>f3 : Symbol(f3, Decl(contextualSignatureWithExtraParameters.ts, 33, 3)) | ||
>a : Symbol(a, Decl(contextualSignatureWithExtraParameters.ts, 40, 4)) | ||
>b : Symbol(b, Decl(contextualSignatureWithExtraParameters.ts, 40, 6)) | ||
|
||
function f4( | ||
>f4 : Symbol(f4, Decl(contextualSignatureWithExtraParameters.ts, 40, 17)) | ||
|
||
cb: ((a: string, b: string) => void) | ((a: string, ...rest: string[]) => void) | ||
>cb : Symbol(cb, Decl(contextualSignatureWithExtraParameters.ts, 42, 12)) | ||
>a : Symbol(a, Decl(contextualSignatureWithExtraParameters.ts, 43, 10)) | ||
>b : Symbol(b, Decl(contextualSignatureWithExtraParameters.ts, 43, 20)) | ||
>a : Symbol(a, Decl(contextualSignatureWithExtraParameters.ts, 43, 45)) | ||
>rest : Symbol(rest, Decl(contextualSignatureWithExtraParameters.ts, 43, 55)) | ||
|
||
) {} | ||
|
||
f4((a) => {}); | ||
>f4 : Symbol(f4, Decl(contextualSignatureWithExtraParameters.ts, 40, 17)) | ||
>a : Symbol(a, Decl(contextualSignatureWithExtraParameters.ts, 46, 4)) | ||
|
||
f4((a, b) => {}); | ||
>f4 : Symbol(f4, Decl(contextualSignatureWithExtraParameters.ts, 40, 17)) | ||
>a : Symbol(a, Decl(contextualSignatureWithExtraParameters.ts, 47, 4)) | ||
>b : Symbol(b, Decl(contextualSignatureWithExtraParameters.ts, 47, 6)) | ||
|
||
function f5( | ||
>f5 : Symbol(f5, Decl(contextualSignatureWithExtraParameters.ts, 47, 17)) | ||
|
||
cb: ((a: string, b: string) => void) | ((...rest: string[]) => void) | ||
>cb : Symbol(cb, Decl(contextualSignatureWithExtraParameters.ts, 49, 12)) | ||
>a : Symbol(a, Decl(contextualSignatureWithExtraParameters.ts, 50, 10)) | ||
>b : Symbol(b, Decl(contextualSignatureWithExtraParameters.ts, 50, 20)) | ||
>rest : Symbol(rest, Decl(contextualSignatureWithExtraParameters.ts, 50, 45)) | ||
|
||
) {} | ||
|
||
f5((a) => {}); | ||
>f5 : Symbol(f5, Decl(contextualSignatureWithExtraParameters.ts, 47, 17)) | ||
>a : Symbol(a, Decl(contextualSignatureWithExtraParameters.ts, 53, 4)) | ||
|
||
f5((a, b) => {}); | ||
>f5 : Symbol(f5, Decl(contextualSignatureWithExtraParameters.ts, 47, 17)) | ||
>a : Symbol(a, Decl(contextualSignatureWithExtraParameters.ts, 54, 4)) | ||
>b : Symbol(b, Decl(contextualSignatureWithExtraParameters.ts, 54, 6)) | ||
|
||
function f6( | ||
>f6 : Symbol(f6, Decl(contextualSignatureWithExtraParameters.ts, 54, 17)) | ||
|
||
cb: ((a: string) => string) | ((a: "a" | "b") => Promise<"a" | "b">) | ||
>cb : Symbol(cb, Decl(contextualSignatureWithExtraParameters.ts, 56, 12)) | ||
>a : Symbol(a, Decl(contextualSignatureWithExtraParameters.ts, 57, 8)) | ||
>a : Symbol(a, Decl(contextualSignatureWithExtraParameters.ts, 57, 34)) | ||
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2018.promise.d.ts, --, --)) | ||
|
||
) {} | ||
|
||
f6(async (a) => a); | ||
>f6 : Symbol(f6, Decl(contextualSignatureWithExtraParameters.ts, 54, 17)) | ||
>a : Symbol(a, Decl(contextualSignatureWithExtraParameters.ts, 60, 10)) | ||
>a : Symbol(a, Decl(contextualSignatureWithExtraParameters.ts, 60, 10)) | ||
|
||
function f7( | ||
>f7 : Symbol(f7, Decl(contextualSignatureWithExtraParameters.ts, 60, 19)) | ||
|
||
cb: ((a: string) => string) | ((a: number) => Generator<number, void, unknown>) | ||
>cb : Symbol(cb, Decl(contextualSignatureWithExtraParameters.ts, 62, 12)) | ||
>a : Symbol(a, Decl(contextualSignatureWithExtraParameters.ts, 63, 8)) | ||
>a : Symbol(a, Decl(contextualSignatureWithExtraParameters.ts, 63, 34)) | ||
>Generator : Symbol(Generator, Decl(lib.es2015.generator.d.ts, --, --)) | ||
|
||
) {} | ||
|
||
f7(function* generator(a) {yield 0}); | ||
>f7 : Symbol(f7, Decl(contextualSignatureWithExtraParameters.ts, 60, 19)) | ||
>generator : Symbol(generator, Decl(contextualSignatureWithExtraParameters.ts, 66, 3)) | ||
>a : Symbol(a, Decl(contextualSignatureWithExtraParameters.ts, 66, 23)) | ||
|
||
function f8( | ||
>f8 : Symbol(f8, Decl(contextualSignatureWithExtraParameters.ts, 66, 37)) | ||
|
||
cb: ((a: string) => string) | ((a: number) => AsyncGenerator<number, void, unknown>) | ||
>cb : Symbol(cb, Decl(contextualSignatureWithExtraParameters.ts, 68, 12)) | ||
>a : Symbol(a, Decl(contextualSignatureWithExtraParameters.ts, 69, 8)) | ||
>a : Symbol(a, Decl(contextualSignatureWithExtraParameters.ts, 69, 34)) | ||
>AsyncGenerator : Symbol(AsyncGenerator, Decl(lib.es2018.asyncgenerator.d.ts, --, --)) | ||
|
||
) {} | ||
|
||
f8(async function* generator(a) {yield 0}); | ||
>f8 : Symbol(f8, Decl(contextualSignatureWithExtraParameters.ts, 66, 37)) | ||
>generator : Symbol(generator, Decl(contextualSignatureWithExtraParameters.ts, 72, 3)) | ||
>a : Symbol(a, Decl(contextualSignatureWithExtraParameters.ts, 72, 29)) | ||
|
||
|
Uh oh!
There was an error while loading. Please reload this page.