Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33694,8 +33694,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}

function getInstantiatedSignatures(signatures: readonly Signature[]) {
const applicableSignatures = filter(signatures, sig => !!sig.typeParameters && hasCorrectTypeArgumentArity(sig, typeArguments));
return sameMap(applicableSignatures, sig => {
const sameTypeAritySignatures = filter(signatures, sig => !!sig.typeParameters && hasCorrectTypeArgumentArity(sig, typeArguments));
if (!sameTypeAritySignatures.length) {
return sameTypeAritySignatures;
}
const applicableSignatures = mapDefined(sameTypeAritySignatures, sig => {
const typeArgumentTypes = checkTypeArguments(sig, typeArguments!, /*reportErrors*/ false);
return typeArgumentTypes && getSignatureInstantiation(sig, typeArgumentTypes, isInJSFile(sig.declaration));
});
Comment on lines +33701 to +33704

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that this still doesn't exactly work like regular overload selection done by chooseOverload. I simply reject signatures that have non-matching constraints on their type params. When overloads are chosen for call expressions etc the first matching overload "wins".

I think that this is actually desirable - since here we still output an intersection of signatures (overloads) and we leave the final overload selection for the time the output type is being used as a call expression.

if (applicableSignatures.length) {
return applicableSignatures;
}
return sameMap(sameTypeAritySignatures, sig => {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've preserved the old behavior here~. If there are some signatures for the given type argument arity but when none of them match... I still gonna report the same error. Perpahs this can be improved further.

const typeArgumentTypes = checkTypeArguments(sig, typeArguments!, /*reportErrors*/ true);
return typeArgumentTypes ? getSignatureInstantiation(sig, typeArgumentTypes, isInJSFile(sig.declaration)) : sig;
});
Expand Down
10 changes: 10 additions & 0 deletions tests/baselines/reference/instantiationExpressions.errors.txt
Original file line number Diff line number Diff line change
Expand Up @@ -225,4 +225,14 @@ tests/cases/conformance/types/typeParameters/typeArgumentLists/instantiationExpr

type T50<U extends string> = typeof g3<U>; // (a: U) => U
type T51<U extends number> = typeof g3<U, any>; // (b: U) => U

// repro #47607#issuecomment-1331744280

type DivElement = { type: 'div' }
interface ElementMap { div: DivElement }

declare function foo<T extends keyof ElementMap>(arg: T): ElementMap[T];
declare function foo<T extends DivElement>(arg: T): T;

type DivFromMap = typeof foo<"div">;

19 changes: 19 additions & 0 deletions tests/baselines/reference/instantiationExpressions.js
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,16 @@ declare const g3: {

type T50<U extends string> = typeof g3<U>; // (a: U) => U
type T51<U extends number> = typeof g3<U, any>; // (b: U) => U

// repro #47607#issuecomment-1331744280

type DivElement = { type: 'div' }
interface ElementMap { div: DivElement }

declare function foo<T extends keyof ElementMap>(arg: T): ElementMap[T];
declare function foo<T extends DivElement>(arg: T): T;

type DivFromMap = typeof foo<"div">;


//// [instantiationExpressions.js]
Expand Down Expand Up @@ -380,3 +390,12 @@ declare const g3: {
};
type T50<U extends string> = typeof g3<U>;
type T51<U extends number> = typeof g3<U, any>;
type DivElement = {
type: 'div';
};
interface ElementMap {
div: DivElement;
}
declare function foo<T extends keyof ElementMap>(arg: T): ElementMap[T];
declare function foo<T extends DivElement>(arg: T): T;
type DivFromMap = typeof foo<"div">;
32 changes: 32 additions & 0 deletions tests/baselines/reference/instantiationExpressions.symbols
Original file line number Diff line number Diff line change
Expand Up @@ -648,3 +648,35 @@ type T51<U extends number> = typeof g3<U, any>; // (b: U) => U
>g3 : Symbol(g3, Decl(instantiationExpressions.ts, 165, 13))
>U : Symbol(U, Decl(instantiationExpressions.ts, 171, 9))

// repro #47607#issuecomment-1331744280

type DivElement = { type: 'div' }
>DivElement : Symbol(DivElement, Decl(instantiationExpressions.ts, 171, 47))
>type : Symbol(type, Decl(instantiationExpressions.ts, 175, 19))

interface ElementMap { div: DivElement }
>ElementMap : Symbol(ElementMap, Decl(instantiationExpressions.ts, 175, 33))
>div : Symbol(ElementMap.div, Decl(instantiationExpressions.ts, 176, 22))
>DivElement : Symbol(DivElement, Decl(instantiationExpressions.ts, 171, 47))

declare function foo<T extends keyof ElementMap>(arg: T): ElementMap[T];
>foo : Symbol(foo, Decl(instantiationExpressions.ts, 176, 40), Decl(instantiationExpressions.ts, 178, 72))
>T : Symbol(T, Decl(instantiationExpressions.ts, 178, 21))
>ElementMap : Symbol(ElementMap, Decl(instantiationExpressions.ts, 175, 33))
>arg : Symbol(arg, Decl(instantiationExpressions.ts, 178, 49))
>T : Symbol(T, Decl(instantiationExpressions.ts, 178, 21))
>ElementMap : Symbol(ElementMap, Decl(instantiationExpressions.ts, 175, 33))
>T : Symbol(T, Decl(instantiationExpressions.ts, 178, 21))

declare function foo<T extends DivElement>(arg: T): T;
>foo : Symbol(foo, Decl(instantiationExpressions.ts, 176, 40), Decl(instantiationExpressions.ts, 178, 72))
>T : Symbol(T, Decl(instantiationExpressions.ts, 179, 21))
>DivElement : Symbol(DivElement, Decl(instantiationExpressions.ts, 171, 47))
>arg : Symbol(arg, Decl(instantiationExpressions.ts, 179, 43))
>T : Symbol(T, Decl(instantiationExpressions.ts, 179, 21))
>T : Symbol(T, Decl(instantiationExpressions.ts, 179, 21))

type DivFromMap = typeof foo<"div">;
>DivFromMap : Symbol(DivFromMap, Decl(instantiationExpressions.ts, 179, 54))
>foo : Symbol(foo, Decl(instantiationExpressions.ts, 176, 40), Decl(instantiationExpressions.ts, 178, 72))

21 changes: 21 additions & 0 deletions tests/baselines/reference/instantiationExpressions.types
Original file line number Diff line number Diff line change
Expand Up @@ -514,3 +514,24 @@ type T51<U extends number> = typeof g3<U, any>; // (b: U) => U
>T51 : new (b: U) => U
>g3 : { <T extends string>(a: T): T; new <T extends number, Q>(b: T): T; }

// repro #47607#issuecomment-1331744280

type DivElement = { type: 'div' }
>DivElement : { type: 'div'; }
>type : "div"

interface ElementMap { div: DivElement }
>div : DivElement

declare function foo<T extends keyof ElementMap>(arg: T): ElementMap[T];
>foo : { <T extends "div">(arg: T): ElementMap[T]; <T extends DivElement>(arg: T): T; }
>arg : T

declare function foo<T extends DivElement>(arg: T): T;
>foo : { <T extends "div">(arg: T): ElementMap[T]; <T extends DivElement>(arg: T): T; }
>arg : T

type DivFromMap = typeof foo<"div">;
>DivFromMap : (arg: "div") => DivElement
>foo : { <T extends "div">(arg: T): ElementMap[T]; <T extends DivElement>(arg: T): T; }

Original file line number Diff line number Diff line change
Expand Up @@ -173,3 +173,13 @@ declare const g3: {

type T50<U extends string> = typeof g3<U>; // (a: U) => U
type T51<U extends number> = typeof g3<U, any>; // (b: U) => U

// repro #47607#issuecomment-1331744280

type DivElement = { type: 'div' }
interface ElementMap { div: DivElement }

declare function foo<T extends keyof ElementMap>(arg: T): ElementMap[T];
declare function foo<T extends DivElement>(arg: T): T;

type DivFromMap = typeof foo<"div">;