Skip to content

Commit 278cb94

Browse files
authored
Properly account for type parameters introduced by contextual types (#59516)
1 parent 5f79e16 commit 278cb94

File tree

4 files changed

+294
-4
lines changed

4 files changed

+294
-4
lines changed

src/compiler/checker.ts

+11-4
Original file line numberDiff line numberDiff line change
@@ -12573,7 +12573,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1257312573
if (!node) {
1257412574
return undefined;
1257512575
}
12576-
switch (node.kind) {
12576+
const kind = node.kind;
12577+
switch (kind) {
1257712578
case SyntaxKind.ClassDeclaration:
1257812579
case SyntaxKind.ClassExpression:
1257912580
case SyntaxKind.InterfaceDeclaration:
@@ -12595,15 +12596,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1259512596
case SyntaxKind.MappedType:
1259612597
case SyntaxKind.ConditionalType: {
1259712598
const outerTypeParameters = getOuterTypeParameters(node, includeThisTypes);
12598-
if (node.kind === SyntaxKind.MappedType) {
12599+
if ((kind === SyntaxKind.FunctionExpression || kind === SyntaxKind.ArrowFunction || isObjectLiteralMethod(node)) && isContextSensitive(node as Expression | MethodDeclaration)) {
12600+
const signature = firstOrUndefined(getSignaturesOfType(getTypeOfSymbol(getSymbolOfDeclaration(node as FunctionLikeDeclaration)), SignatureKind.Call));
12601+
if (signature && signature.typeParameters) {
12602+
return [...(outerTypeParameters || emptyArray), ...signature.typeParameters];
12603+
}
12604+
}
12605+
if (kind === SyntaxKind.MappedType) {
1259912606
return append(outerTypeParameters, getDeclaredTypeOfTypeParameter(getSymbolOfDeclaration((node as MappedTypeNode).typeParameter)));
1260012607
}
12601-
else if (node.kind === SyntaxKind.ConditionalType) {
12608+
else if (kind === SyntaxKind.ConditionalType) {
1260212609
return concatenate(outerTypeParameters, getInferTypeParameters(node as ConditionalTypeNode));
1260312610
}
1260412611
const outerAndOwnTypeParameters = appendTypeParameters(outerTypeParameters, getEffectiveTypeParameterDeclarations(node as DeclarationWithTypeParameters));
1260512612
const thisType = includeThisTypes &&
12606-
(node.kind === SyntaxKind.ClassDeclaration || node.kind === SyntaxKind.ClassExpression || node.kind === SyntaxKind.InterfaceDeclaration || isJSConstructor(node)) &&
12613+
(kind === SyntaxKind.ClassDeclaration || kind === SyntaxKind.ClassExpression || kind === SyntaxKind.InterfaceDeclaration || isJSConstructor(node)) &&
1260712614
getDeclaredTypeOfClassOrInterface(getSymbolOfDeclaration(node as ClassLikeDeclaration | InterfaceDeclaration)).thisType;
1260812615
return thisType ? append(outerAndOwnTypeParameters, thisType) : outerAndOwnTypeParameters;
1260912616
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
//// [tests/cases/compiler/contextualOuterTypeParameters.ts] ////
2+
3+
=== contextualOuterTypeParameters.ts ===
4+
// https://github.com/microsoft/TypeScript/issues/59450
5+
6+
declare function f(fun: <T>(t: T) => void): void
7+
>f : Symbol(f, Decl(contextualOuterTypeParameters.ts, 0, 0))
8+
>fun : Symbol(fun, Decl(contextualOuterTypeParameters.ts, 2, 19))
9+
>T : Symbol(T, Decl(contextualOuterTypeParameters.ts, 2, 25))
10+
>t : Symbol(t, Decl(contextualOuterTypeParameters.ts, 2, 28))
11+
>T : Symbol(T, Decl(contextualOuterTypeParameters.ts, 2, 25))
12+
13+
f(t => {
14+
>f : Symbol(f, Decl(contextualOuterTypeParameters.ts, 0, 0))
15+
>t : Symbol(t, Decl(contextualOuterTypeParameters.ts, 4, 2))
16+
17+
type isArray = (typeof t)[] extends string[] ? true : false;
18+
>isArray : Symbol(isArray, Decl(contextualOuterTypeParameters.ts, 4, 8))
19+
>t : Symbol(t, Decl(contextualOuterTypeParameters.ts, 4, 2))
20+
21+
type IsObject = { x: typeof t } extends { x: string } ? true : false;
22+
>IsObject : Symbol(IsObject, Decl(contextualOuterTypeParameters.ts, 5, 64))
23+
>x : Symbol(x, Decl(contextualOuterTypeParameters.ts, 6, 21))
24+
>t : Symbol(t, Decl(contextualOuterTypeParameters.ts, 4, 2))
25+
>x : Symbol(x, Decl(contextualOuterTypeParameters.ts, 6, 45))
26+
27+
});
28+
29+
const fn1: <T>(x: T) => void = t => {
30+
>fn1 : Symbol(fn1, Decl(contextualOuterTypeParameters.ts, 9, 5))
31+
>T : Symbol(T, Decl(contextualOuterTypeParameters.ts, 9, 12))
32+
>x : Symbol(x, Decl(contextualOuterTypeParameters.ts, 9, 15))
33+
>T : Symbol(T, Decl(contextualOuterTypeParameters.ts, 9, 12))
34+
>t : Symbol(t, Decl(contextualOuterTypeParameters.ts, 9, 30))
35+
36+
type isArray = (typeof t)[] extends string[] ? true : false;
37+
>isArray : Symbol(isArray, Decl(contextualOuterTypeParameters.ts, 9, 37))
38+
>t : Symbol(t, Decl(contextualOuterTypeParameters.ts, 9, 30))
39+
40+
type IsObject = { x: typeof t } extends { x: string } ? true : false;
41+
>IsObject : Symbol(IsObject, Decl(contextualOuterTypeParameters.ts, 10, 64))
42+
>x : Symbol(x, Decl(contextualOuterTypeParameters.ts, 11, 21))
43+
>t : Symbol(t, Decl(contextualOuterTypeParameters.ts, 9, 30))
44+
>x : Symbol(x, Decl(contextualOuterTypeParameters.ts, 11, 45))
45+
46+
};
47+
48+
const fn2: <T>(x: T) => void = function test(t) {
49+
>fn2 : Symbol(fn2, Decl(contextualOuterTypeParameters.ts, 14, 5))
50+
>T : Symbol(T, Decl(contextualOuterTypeParameters.ts, 14, 12))
51+
>x : Symbol(x, Decl(contextualOuterTypeParameters.ts, 14, 15))
52+
>T : Symbol(T, Decl(contextualOuterTypeParameters.ts, 14, 12))
53+
>test : Symbol(test, Decl(contextualOuterTypeParameters.ts, 14, 30))
54+
>t : Symbol(t, Decl(contextualOuterTypeParameters.ts, 14, 45))
55+
56+
type isArray = (typeof t)[] extends string[] ? true : false;
57+
>isArray : Symbol(isArray, Decl(contextualOuterTypeParameters.ts, 14, 49))
58+
>t : Symbol(t, Decl(contextualOuterTypeParameters.ts, 14, 45))
59+
60+
type IsObject = { x: typeof t } extends { x: string } ? true : false;
61+
>IsObject : Symbol(IsObject, Decl(contextualOuterTypeParameters.ts, 15, 64))
62+
>x : Symbol(x, Decl(contextualOuterTypeParameters.ts, 16, 21))
63+
>t : Symbol(t, Decl(contextualOuterTypeParameters.ts, 14, 45))
64+
>x : Symbol(x, Decl(contextualOuterTypeParameters.ts, 16, 45))
65+
66+
};
67+
68+
const obj: { f: <T>(x: T) => void } = {
69+
>obj : Symbol(obj, Decl(contextualOuterTypeParameters.ts, 19, 5))
70+
>f : Symbol(f, Decl(contextualOuterTypeParameters.ts, 19, 12))
71+
>T : Symbol(T, Decl(contextualOuterTypeParameters.ts, 19, 17))
72+
>x : Symbol(x, Decl(contextualOuterTypeParameters.ts, 19, 20))
73+
>T : Symbol(T, Decl(contextualOuterTypeParameters.ts, 19, 17))
74+
75+
f(t) {
76+
>f : Symbol(f, Decl(contextualOuterTypeParameters.ts, 19, 39))
77+
>t : Symbol(t, Decl(contextualOuterTypeParameters.ts, 20, 6))
78+
79+
type isArray = (typeof t)[] extends string[] ? true : false;
80+
>isArray : Symbol(isArray, Decl(contextualOuterTypeParameters.ts, 20, 10))
81+
>t : Symbol(t, Decl(contextualOuterTypeParameters.ts, 20, 6))
82+
83+
type IsObject = { x: typeof t } extends { x: string } ? true : false;
84+
>IsObject : Symbol(IsObject, Decl(contextualOuterTypeParameters.ts, 21, 68))
85+
>x : Symbol(x, Decl(contextualOuterTypeParameters.ts, 22, 25))
86+
>t : Symbol(t, Decl(contextualOuterTypeParameters.ts, 20, 6))
87+
>x : Symbol(x, Decl(contextualOuterTypeParameters.ts, 22, 49))
88+
}
89+
};
90+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
//// [tests/cases/compiler/contextualOuterTypeParameters.ts] ////
2+
3+
=== contextualOuterTypeParameters.ts ===
4+
// https://github.com/microsoft/TypeScript/issues/59450
5+
6+
declare function f(fun: <T>(t: T) => void): void
7+
>f : (fun: <T>(t: T) => void) => void
8+
> : ^ ^^ ^^^^^
9+
>fun : <T>(t: T) => void
10+
> : ^ ^^ ^^ ^^^^^
11+
>t : T
12+
> : ^
13+
14+
f(t => {
15+
>f(t => { type isArray = (typeof t)[] extends string[] ? true : false; type IsObject = { x: typeof t } extends { x: string } ? true : false;}) : void
16+
> : ^^^^
17+
>f : (fun: <T>(t: T) => void) => void
18+
> : ^ ^^ ^^^^^
19+
>t => { type isArray = (typeof t)[] extends string[] ? true : false; type IsObject = { x: typeof t } extends { x: string } ? true : false;} : <T>(t: T) => void
20+
> : ^ ^^ ^^^^^^^^^^^^
21+
>t : T
22+
> : ^
23+
24+
type isArray = (typeof t)[] extends string[] ? true : false;
25+
>isArray : T[] extends string[] ? true : false
26+
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
27+
>t : T
28+
> : ^
29+
>true : true
30+
> : ^^^^
31+
>false : false
32+
> : ^^^^^
33+
34+
type IsObject = { x: typeof t } extends { x: string } ? true : false;
35+
>IsObject : { x: typeof t; } extends { x: string; } ? true : false
36+
> : ^^^^^ ^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^
37+
>x : T
38+
> : ^
39+
>t : T
40+
> : ^
41+
>x : string
42+
> : ^^^^^^
43+
>true : true
44+
> : ^^^^
45+
>false : false
46+
> : ^^^^^
47+
48+
});
49+
50+
const fn1: <T>(x: T) => void = t => {
51+
>fn1 : <T>(x: T) => void
52+
> : ^ ^^ ^^ ^^^^^
53+
>x : T
54+
> : ^
55+
>t => { type isArray = (typeof t)[] extends string[] ? true : false; type IsObject = { x: typeof t } extends { x: string } ? true : false;} : <T>(t: T) => void
56+
> : ^ ^^ ^^^^^^^^^^^^
57+
>t : T
58+
> : ^
59+
60+
type isArray = (typeof t)[] extends string[] ? true : false;
61+
>isArray : T[] extends string[] ? true : false
62+
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
63+
>t : T
64+
> : ^
65+
>true : true
66+
> : ^^^^
67+
>false : false
68+
> : ^^^^^
69+
70+
type IsObject = { x: typeof t } extends { x: string } ? true : false;
71+
>IsObject : { x: typeof t; } extends { x: string; } ? true : false
72+
> : ^^^^^ ^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^
73+
>x : T
74+
> : ^
75+
>t : T
76+
> : ^
77+
>x : string
78+
> : ^^^^^^
79+
>true : true
80+
> : ^^^^
81+
>false : false
82+
> : ^^^^^
83+
84+
};
85+
86+
const fn2: <T>(x: T) => void = function test(t) {
87+
>fn2 : <T>(x: T) => void
88+
> : ^ ^^ ^^ ^^^^^
89+
>x : T
90+
> : ^
91+
>function test(t) { type isArray = (typeof t)[] extends string[] ? true : false; type IsObject = { x: typeof t } extends { x: string } ? true : false;} : <T>(t: T) => void
92+
> : ^ ^^ ^^^^^^^^^^^^
93+
>test : <T>(t: T) => void
94+
> : ^ ^^ ^^^^^^^^^^^^
95+
>t : T
96+
> : ^
97+
98+
type isArray = (typeof t)[] extends string[] ? true : false;
99+
>isArray : T[] extends string[] ? true : false
100+
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
101+
>t : T
102+
> : ^
103+
>true : true
104+
> : ^^^^
105+
>false : false
106+
> : ^^^^^
107+
108+
type IsObject = { x: typeof t } extends { x: string } ? true : false;
109+
>IsObject : { x: typeof t; } extends { x: string; } ? true : false
110+
> : ^^^^^ ^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^
111+
>x : T
112+
> : ^
113+
>t : T
114+
> : ^
115+
>x : string
116+
> : ^^^^^^
117+
>true : true
118+
> : ^^^^
119+
>false : false
120+
> : ^^^^^
121+
122+
};
123+
124+
const obj: { f: <T>(x: T) => void } = {
125+
>obj : { f: <T>(x: T) => void; }
126+
> : ^^^^^ ^^^
127+
>f : <T>(x: T) => void
128+
> : ^ ^^ ^^ ^^^^^
129+
>x : T
130+
> : ^
131+
>{ f(t) { type isArray = (typeof t)[] extends string[] ? true : false; type IsObject = { x: typeof t } extends { x: string } ? true : false; }} : { f<T>(t: T): void; }
132+
> : ^^^^ ^^ ^^^^^^^^^^^^^
133+
134+
f(t) {
135+
>f : <T>(t: T) => void
136+
> : ^ ^^ ^^^^^^^^^^^^
137+
>t : T
138+
> : ^
139+
140+
type isArray = (typeof t)[] extends string[] ? true : false;
141+
>isArray : T[] extends string[] ? true : false
142+
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
143+
>t : T
144+
> : ^
145+
>true : true
146+
> : ^^^^
147+
>false : false
148+
> : ^^^^^
149+
150+
type IsObject = { x: typeof t } extends { x: string } ? true : false;
151+
>IsObject : { x: typeof t; } extends { x: string; } ? true : false
152+
> : ^^^^^ ^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^
153+
>x : T
154+
> : ^
155+
>t : T
156+
> : ^
157+
>x : string
158+
> : ^^^^^^
159+
>true : true
160+
> : ^^^^
161+
>false : false
162+
> : ^^^^^
163+
}
164+
};
165+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// @strict: true
2+
// @noemit: true
3+
4+
// https://github.com/microsoft/TypeScript/issues/59450
5+
6+
declare function f(fun: <T>(t: T) => void): void
7+
8+
f(t => {
9+
type isArray = (typeof t)[] extends string[] ? true : false;
10+
type IsObject = { x: typeof t } extends { x: string } ? true : false;
11+
});
12+
13+
const fn1: <T>(x: T) => void = t => {
14+
type isArray = (typeof t)[] extends string[] ? true : false;
15+
type IsObject = { x: typeof t } extends { x: string } ? true : false;
16+
};
17+
18+
const fn2: <T>(x: T) => void = function test(t) {
19+
type isArray = (typeof t)[] extends string[] ? true : false;
20+
type IsObject = { x: typeof t } extends { x: string } ? true : false;
21+
};
22+
23+
const obj: { f: <T>(x: T) => void } = {
24+
f(t) {
25+
type isArray = (typeof t)[] extends string[] ? true : false;
26+
type IsObject = { x: typeof t } extends { x: string } ? true : false;
27+
}
28+
};

0 commit comments

Comments
 (0)