Skip to content

Commit 9598d35

Browse files
authored
Avoid getting single call signatures when parameter types are the same (#58392)
1 parent fd81d04 commit 9598d35

5 files changed

+320
-1
lines changed

src/compiler/checker.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20770,7 +20770,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2077020770
for (let i = 0; i < paramCount; i++) {
2077120771
const sourceType = i === restIndex ? getRestOrAnyTypeAtPosition(source, i) : tryGetTypeAtPosition(source, i);
2077220772
const targetType = i === restIndex ? getRestOrAnyTypeAtPosition(target, i) : tryGetTypeAtPosition(target, i);
20773-
if (sourceType && targetType) {
20773+
if (sourceType && targetType && (sourceType !== targetType || checkMode & SignatureCheckMode.StrictArity)) {
2077420774
// In order to ensure that any generic type Foo<T> is at least co-variant with respect to T no matter
2077520775
// how Foo uses T, we need to relate parameters bi-variantly (given that parameters are input positions,
2077620776
// they naturally relate only contra-variantly). However, if the source and target parameters both have
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
//// [tests/cases/compiler/classReferencedInContextualParameterWithinItsOwnBaseExpression.ts] ////
2+
3+
//// [classReferencedInContextualParameterWithinItsOwnBaseExpression.ts]
4+
interface Pretty<To> {
5+
(a: To): string;
6+
}
7+
8+
interface Schema<A> {
9+
readonly pretty?: Pretty<A>;
10+
}
11+
12+
interface Class<A> {
13+
new (): A;
14+
}
15+
16+
declare const Class: <Self>(
17+
identifier: string,
18+
) => <Fields>(
19+
fields: Fields,
20+
annotations?: Schema<Self>,
21+
) => Class<OutputFrom<Fields>>;
22+
23+
type Type<TOutput> = {
24+
_TOutput: TOutput;
25+
};
26+
27+
type OutputFrom<TFields> = {
28+
[K in keyof TFields]: "_TOutput" extends keyof TFields[K]
29+
? TFields[K]["_TOutput"]
30+
: never;
31+
};
32+
33+
declare function string(): Type<string>;
34+
35+
export class A extends Class<A>("A")(
36+
{ a: string },
37+
{
38+
pretty: (a) => JSON.stringify(a),
39+
},
40+
) {}
41+
42+
43+
44+
45+
//// [classReferencedInContextualParameterWithinItsOwnBaseExpression.d.ts]
46+
interface Pretty<To> {
47+
(a: To): string;
48+
}
49+
interface Schema<A> {
50+
readonly pretty?: Pretty<A>;
51+
}
52+
interface Class<A> {
53+
new (): A;
54+
}
55+
declare const Class: <Self>(identifier: string) => <Fields>(fields: Fields, annotations?: Schema<Self>) => Class<OutputFrom<Fields>>;
56+
type Type<TOutput> = {
57+
_TOutput: TOutput;
58+
};
59+
type OutputFrom<TFields> = {
60+
[K in keyof TFields]: "_TOutput" extends keyof TFields[K] ? TFields[K]["_TOutput"] : never;
61+
};
62+
declare function string(): Type<string>;
63+
declare const A_base: Class<OutputFrom<{
64+
a: typeof string;
65+
}>>;
66+
export declare class A extends A_base {
67+
}
68+
export {};
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
//// [tests/cases/compiler/classReferencedInContextualParameterWithinItsOwnBaseExpression.ts] ////
2+
3+
=== classReferencedInContextualParameterWithinItsOwnBaseExpression.ts ===
4+
interface Pretty<To> {
5+
>Pretty : Symbol(Pretty, Decl(classReferencedInContextualParameterWithinItsOwnBaseExpression.ts, 0, 0))
6+
>To : Symbol(To, Decl(classReferencedInContextualParameterWithinItsOwnBaseExpression.ts, 0, 17))
7+
8+
(a: To): string;
9+
>a : Symbol(a, Decl(classReferencedInContextualParameterWithinItsOwnBaseExpression.ts, 1, 3))
10+
>To : Symbol(To, Decl(classReferencedInContextualParameterWithinItsOwnBaseExpression.ts, 0, 17))
11+
}
12+
13+
interface Schema<A> {
14+
>Schema : Symbol(Schema, Decl(classReferencedInContextualParameterWithinItsOwnBaseExpression.ts, 2, 1))
15+
>A : Symbol(A, Decl(classReferencedInContextualParameterWithinItsOwnBaseExpression.ts, 4, 17))
16+
17+
readonly pretty?: Pretty<A>;
18+
>pretty : Symbol(Schema.pretty, Decl(classReferencedInContextualParameterWithinItsOwnBaseExpression.ts, 4, 21))
19+
>Pretty : Symbol(Pretty, Decl(classReferencedInContextualParameterWithinItsOwnBaseExpression.ts, 0, 0))
20+
>A : Symbol(A, Decl(classReferencedInContextualParameterWithinItsOwnBaseExpression.ts, 4, 17))
21+
}
22+
23+
interface Class<A> {
24+
>Class : Symbol(Class, Decl(classReferencedInContextualParameterWithinItsOwnBaseExpression.ts, 6, 1), Decl(classReferencedInContextualParameterWithinItsOwnBaseExpression.ts, 12, 13))
25+
>A : Symbol(A, Decl(classReferencedInContextualParameterWithinItsOwnBaseExpression.ts, 8, 16))
26+
27+
new (): A;
28+
>A : Symbol(A, Decl(classReferencedInContextualParameterWithinItsOwnBaseExpression.ts, 8, 16))
29+
}
30+
31+
declare const Class: <Self>(
32+
>Class : Symbol(Class, Decl(classReferencedInContextualParameterWithinItsOwnBaseExpression.ts, 6, 1), Decl(classReferencedInContextualParameterWithinItsOwnBaseExpression.ts, 12, 13))
33+
>Self : Symbol(Self, Decl(classReferencedInContextualParameterWithinItsOwnBaseExpression.ts, 12, 22))
34+
35+
identifier: string,
36+
>identifier : Symbol(identifier, Decl(classReferencedInContextualParameterWithinItsOwnBaseExpression.ts, 12, 28))
37+
38+
) => <Fields>(
39+
>Fields : Symbol(Fields, Decl(classReferencedInContextualParameterWithinItsOwnBaseExpression.ts, 14, 6))
40+
41+
fields: Fields,
42+
>fields : Symbol(fields, Decl(classReferencedInContextualParameterWithinItsOwnBaseExpression.ts, 14, 14))
43+
>Fields : Symbol(Fields, Decl(classReferencedInContextualParameterWithinItsOwnBaseExpression.ts, 14, 6))
44+
45+
annotations?: Schema<Self>,
46+
>annotations : Symbol(annotations, Decl(classReferencedInContextualParameterWithinItsOwnBaseExpression.ts, 15, 17))
47+
>Schema : Symbol(Schema, Decl(classReferencedInContextualParameterWithinItsOwnBaseExpression.ts, 2, 1))
48+
>Self : Symbol(Self, Decl(classReferencedInContextualParameterWithinItsOwnBaseExpression.ts, 12, 22))
49+
50+
) => Class<OutputFrom<Fields>>;
51+
>Class : Symbol(Class, Decl(classReferencedInContextualParameterWithinItsOwnBaseExpression.ts, 6, 1), Decl(classReferencedInContextualParameterWithinItsOwnBaseExpression.ts, 12, 13))
52+
>OutputFrom : Symbol(OutputFrom, Decl(classReferencedInContextualParameterWithinItsOwnBaseExpression.ts, 21, 2))
53+
>Fields : Symbol(Fields, Decl(classReferencedInContextualParameterWithinItsOwnBaseExpression.ts, 14, 6))
54+
55+
type Type<TOutput> = {
56+
>Type : Symbol(Type, Decl(classReferencedInContextualParameterWithinItsOwnBaseExpression.ts, 17, 31))
57+
>TOutput : Symbol(TOutput, Decl(classReferencedInContextualParameterWithinItsOwnBaseExpression.ts, 19, 10))
58+
59+
_TOutput: TOutput;
60+
>_TOutput : Symbol(_TOutput, Decl(classReferencedInContextualParameterWithinItsOwnBaseExpression.ts, 19, 22))
61+
>TOutput : Symbol(TOutput, Decl(classReferencedInContextualParameterWithinItsOwnBaseExpression.ts, 19, 10))
62+
63+
};
64+
65+
type OutputFrom<TFields> = {
66+
>OutputFrom : Symbol(OutputFrom, Decl(classReferencedInContextualParameterWithinItsOwnBaseExpression.ts, 21, 2))
67+
>TFields : Symbol(TFields, Decl(classReferencedInContextualParameterWithinItsOwnBaseExpression.ts, 23, 16))
68+
69+
[K in keyof TFields]: "_TOutput" extends keyof TFields[K]
70+
>K : Symbol(K, Decl(classReferencedInContextualParameterWithinItsOwnBaseExpression.ts, 24, 3))
71+
>TFields : Symbol(TFields, Decl(classReferencedInContextualParameterWithinItsOwnBaseExpression.ts, 23, 16))
72+
>TFields : Symbol(TFields, Decl(classReferencedInContextualParameterWithinItsOwnBaseExpression.ts, 23, 16))
73+
>K : Symbol(K, Decl(classReferencedInContextualParameterWithinItsOwnBaseExpression.ts, 24, 3))
74+
75+
? TFields[K]["_TOutput"]
76+
>TFields : Symbol(TFields, Decl(classReferencedInContextualParameterWithinItsOwnBaseExpression.ts, 23, 16))
77+
>K : Symbol(K, Decl(classReferencedInContextualParameterWithinItsOwnBaseExpression.ts, 24, 3))
78+
79+
: never;
80+
};
81+
82+
declare function string(): Type<string>;
83+
>string : Symbol(string, Decl(classReferencedInContextualParameterWithinItsOwnBaseExpression.ts, 27, 2))
84+
>Type : Symbol(Type, Decl(classReferencedInContextualParameterWithinItsOwnBaseExpression.ts, 17, 31))
85+
86+
export class A extends Class<A>("A")(
87+
>A : Symbol(A, Decl(classReferencedInContextualParameterWithinItsOwnBaseExpression.ts, 29, 40))
88+
>Class : Symbol(Class, Decl(classReferencedInContextualParameterWithinItsOwnBaseExpression.ts, 6, 1), Decl(classReferencedInContextualParameterWithinItsOwnBaseExpression.ts, 12, 13))
89+
>A : Symbol(A, Decl(classReferencedInContextualParameterWithinItsOwnBaseExpression.ts, 29, 40))
90+
91+
{ a: string },
92+
>a : Symbol(a, Decl(classReferencedInContextualParameterWithinItsOwnBaseExpression.ts, 32, 3))
93+
>string : Symbol(string, Decl(classReferencedInContextualParameterWithinItsOwnBaseExpression.ts, 27, 2))
94+
{
95+
pretty: (a) => JSON.stringify(a),
96+
>pretty : Symbol(pretty, Decl(classReferencedInContextualParameterWithinItsOwnBaseExpression.ts, 33, 3))
97+
>a : Symbol(a, Decl(classReferencedInContextualParameterWithinItsOwnBaseExpression.ts, 34, 13))
98+
>JSON.stringify : Symbol(JSON.stringify, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
99+
>JSON : Symbol(JSON, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
100+
>stringify : Symbol(JSON.stringify, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
101+
>a : Symbol(a, Decl(classReferencedInContextualParameterWithinItsOwnBaseExpression.ts, 34, 13))
102+
103+
},
104+
) {}
105+
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
//// [tests/cases/compiler/classReferencedInContextualParameterWithinItsOwnBaseExpression.ts] ////
2+
3+
=== classReferencedInContextualParameterWithinItsOwnBaseExpression.ts ===
4+
interface Pretty<To> {
5+
(a: To): string;
6+
>a : To
7+
> : ^^
8+
}
9+
10+
interface Schema<A> {
11+
readonly pretty?: Pretty<A>;
12+
>pretty : Pretty<A> | undefined
13+
> : ^^^^^^^^^^^^^^^^^^^^^
14+
}
15+
16+
interface Class<A> {
17+
new (): A;
18+
}
19+
20+
declare const Class: <Self>(
21+
>Class : <Self>(identifier: string) => <Fields>(fields: Fields, annotations?: Schema<Self>) => Class<OutputFrom<Fields>>
22+
> : ^ ^^ ^^ ^^^^^
23+
24+
identifier: string,
25+
>identifier : string
26+
> : ^^^^^^
27+
28+
) => <Fields>(
29+
fields: Fields,
30+
>fields : Fields
31+
> : ^^^^^^
32+
33+
annotations?: Schema<Self>,
34+
>annotations : Schema<Self> | undefined
35+
> : ^^^^^^^^^^^^^^^^^^^^^^^^
36+
37+
) => Class<OutputFrom<Fields>>;
38+
39+
type Type<TOutput> = {
40+
>Type : Type<TOutput>
41+
> : ^^^^^^^^^^^^^
42+
43+
_TOutput: TOutput;
44+
>_TOutput : TOutput
45+
> : ^^^^^^^
46+
47+
};
48+
49+
type OutputFrom<TFields> = {
50+
>OutputFrom : OutputFrom<TFields>
51+
> : ^^^^^^^^^^^^^^^^^^^
52+
53+
[K in keyof TFields]: "_TOutput" extends keyof TFields[K]
54+
? TFields[K]["_TOutput"]
55+
: never;
56+
};
57+
58+
declare function string(): Type<string>;
59+
>string : () => Type<string>
60+
> : ^^^^^^
61+
62+
export class A extends Class<A>("A")(
63+
>A : A
64+
> : ^
65+
>Class<A>("A")( { a: string }, { pretty: (a) => JSON.stringify(a), },) : OutputFrom<{ a: () => Type<string>; }>
66+
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
67+
>Class<A>("A") : <Fields>(fields: Fields, annotations?: Schema<A> | undefined) => Class<OutputFrom<Fields>>
68+
> : ^^^^^^^^^ ^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
69+
>Class : <Self>(identifier: string) => <Fields>(fields: Fields, annotations?: Schema<Self>) => Class<OutputFrom<Fields>>
70+
> : ^ ^^ ^^ ^^^^^^ ^^ ^^ ^^ ^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
71+
>"A" : "A"
72+
> : ^^^
73+
74+
{ a: string },
75+
>{ a: string } : { a: () => Type<string>; }
76+
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^
77+
>a : () => Type<string>
78+
> : ^^^^^^^^^^^^^^^^^^
79+
>string : () => Type<string>
80+
> : ^^^^^^^^^^^^^^^^^^
81+
{
82+
>{ pretty: (a) => JSON.stringify(a), } : { pretty: (a: A) => string; }
83+
> : ^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^
84+
85+
pretty: (a) => JSON.stringify(a),
86+
>pretty : (a: A) => string
87+
> : ^ ^^^^^^^^^^^^^^
88+
>(a) => JSON.stringify(a) : (a: A) => string
89+
> : ^ ^^^^^^^^^^^^^^
90+
>a : A
91+
> : ^
92+
>JSON.stringify(a) : string
93+
> : ^^^^^^
94+
>JSON.stringify : { (value: any, replacer?: (this: any, key: string, value: any) => any, space?: string | number): string; (value: any, replacer?: (number | string)[] | null, space?: string | number): string; }
95+
> : ^^^ ^^ ^^ ^^^ ^^ ^^^ ^^^^^^^^^^^^ ^^ ^^ ^^^ ^^ ^^^ ^^^^^^^^^^^^
96+
>JSON : JSON
97+
> : ^^^^
98+
>stringify : { (value: any, replacer?: (this: any, key: string, value: any) => any, space?: string | number): string; (value: any, replacer?: (number | string)[] | null, space?: string | number): string; }
99+
> : ^^^ ^^ ^^ ^^^ ^^ ^^^ ^^^^^^^^^^^^ ^^ ^^ ^^^ ^^ ^^^ ^^^^^^^^^^^^
100+
>a : A
101+
> : ^
102+
103+
},
104+
) {}
105+
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// @strict: true
2+
// @declaration: true
3+
// @emitDeclarationOnly: true
4+
5+
interface Pretty<To> {
6+
(a: To): string;
7+
}
8+
9+
interface Schema<A> {
10+
readonly pretty?: Pretty<A>;
11+
}
12+
13+
interface Class<A> {
14+
new (): A;
15+
}
16+
17+
declare const Class: <Self>(
18+
identifier: string,
19+
) => <Fields>(
20+
fields: Fields,
21+
annotations?: Schema<Self>,
22+
) => Class<OutputFrom<Fields>>;
23+
24+
type Type<TOutput> = {
25+
_TOutput: TOutput;
26+
};
27+
28+
type OutputFrom<TFields> = {
29+
[K in keyof TFields]: "_TOutput" extends keyof TFields[K]
30+
? TFields[K]["_TOutput"]
31+
: never;
32+
};
33+
34+
declare function string(): Type<string>;
35+
36+
export class A extends Class<A>("A")(
37+
{ a: string },
38+
{
39+
pretty: (a) => JSON.stringify(a),
40+
},
41+
) {}

0 commit comments

Comments
 (0)