Skip to content

Commit 94709a6

Browse files
committed
Assign contextual parameter types to functions with type parameters
1 parent b504a1e commit 94709a6

7 files changed

Lines changed: 670 additions & 17 deletions

File tree

src/compiler/checker.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21025,7 +21025,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2102521025
}
2102621026

2102721027
function hasContextSensitiveReturnExpression(node: FunctionLikeDeclaration) {
21028-
if (node.typeParameters || getEffectiveReturnTypeNode(node) || !node.body) {
21028+
if (getEffectiveReturnTypeNode(node) || !node.body) {
2102921029
return false;
2103021030
}
2103121031
if (node.body.kind !== SyntaxKind.Block) {

src/compiler/utilities.ts

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10783,20 +10783,17 @@ export function getContainingNodeArray(node: Node): NodeArray<Node> | undefined
1078310783

1078410784
/** @internal */
1078510785
export function hasContextSensitiveParameters(node: FunctionLikeDeclaration): boolean {
10786-
// Functions with type parameters are not context sensitive.
10787-
if (!node.typeParameters) {
10788-
// Functions with any parameters that lack type annotations are context sensitive.
10789-
if (some(node.parameters, p => !getEffectiveTypeAnnotationNode(p))) {
10786+
// Functions with any parameters that lack type annotations are context sensitive.
10787+
if (some(node.parameters, p => !getEffectiveTypeAnnotationNode(p))) {
10788+
return true;
10789+
}
10790+
if (node.kind !== SyntaxKind.ArrowFunction) {
10791+
// If the first parameter is not an explicit 'this' parameter, then the function has
10792+
// an implicit 'this' parameter which is subject to contextual typing.
10793+
const parameter = firstOrUndefined(node.parameters);
10794+
if (!(parameter && parameterIsThisKeyword(parameter))) {
1079010795
return true;
1079110796
}
10792-
if (node.kind !== SyntaxKind.ArrowFunction) {
10793-
// If the first parameter is not an explicit 'this' parameter, then the function has
10794-
// an implicit 'this' parameter which is subject to contextual typing.
10795-
const parameter = firstOrUndefined(node.parameters);
10796-
if (!(parameter && parameterIsThisKeyword(parameter))) {
10797-
return true;
10798-
}
10799-
}
1080010797
}
1080110798
return false;
1080210799
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
//// [tests/cases/compiler/contextualTypingGenericFunction2.ts] ////
2+
3+
//// [contextualTypingGenericFunction2.ts]
4+
// https://github.com/microsoft/TypeScript/issues/61791
5+
6+
declare const fn1: <T, Args extends Array<any>, Ret>(
7+
self: T,
8+
body: (this: T, ...args: Args) => Ret,
9+
) => (...args: Args) => Ret;
10+
11+
export const ok1 = fn1({ message: "foo" }, function (n: number) {
12+
this.message;
13+
});
14+
15+
export const ok2 = fn1({ message: "foo" }, function <N>(n: N) {
16+
this.message;
17+
});
18+
19+
declare const fn2: <Args extends Array<any>, Ret>(
20+
body: (first: string, ...args: Args) => Ret,
21+
) => (...args: Args) => Ret;
22+
23+
export const ok3 = fn2(function <N>(first, n: N) {});
24+
25+
declare const fn3: <Args extends Array<any>, Ret>(
26+
body: (...args: Args) => (arg: string) => Ret,
27+
) => (...args: Args) => Ret;
28+
29+
export const ok4 = fn3(function <N>(n: N) {
30+
return (arg) => {
31+
return 10
32+
}
33+
});
34+
35+
declare function fn4<T, P>(config: {
36+
context: T;
37+
callback: (params: P) => (context: T, params: P) => number;
38+
}): (params: P) => number;
39+
40+
export const ok5 = fn4({
41+
context: 1,
42+
callback: <T,>(params: T) => {
43+
return (a, b) => a + 1;
44+
},
45+
});
46+
47+
declare const fnGen1: <T, Args extends Array<any>, Ret>(
48+
self: T,
49+
body: (this: T, ...args: Args) => Generator<any, Ret, never>,
50+
) => (...args: Args) => Ret;
51+
52+
export const ok6 = fnGen1({ message: "foo" }, function* (n: number) {
53+
this.message;
54+
});
55+
56+
export const ok7 = fnGen1({ message: "foo" }, function* <N>(n: N) {
57+
this.message;
58+
});
59+
60+
61+
62+
63+
//// [contextualTypingGenericFunction2.d.ts]
64+
export declare const ok1: (n: number) => void;
65+
export declare const ok2: (n: any) => void;
66+
export declare const ok3: <N>(n: N) => void;
67+
export declare const ok4: <N>(n: N) => number;
68+
export declare const ok5: (params: T) => number;
69+
export declare const ok6: (n: number) => void;
70+
export declare const ok7: (n: any) => void;
71+
72+
73+
//// [DtsFileErrors]
74+
75+
76+
contextualTypingGenericFunction2.d.ts(5,36): error TS2304: Cannot find name 'T'.
77+
78+
79+
==== contextualTypingGenericFunction2.d.ts (1 errors) ====
80+
export declare const ok1: (n: number) => void;
81+
export declare const ok2: (n: any) => void;
82+
export declare const ok3: <N>(n: N) => void;
83+
export declare const ok4: <N>(n: N) => number;
84+
export declare const ok5: (params: T) => number;
85+
~
86+
!!! error TS2304: Cannot find name 'T'.
87+
export declare const ok6: (n: number) => void;
88+
export declare const ok7: (n: any) => void;
89+
Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
//// [tests/cases/compiler/contextualTypingGenericFunction2.ts] ////
2+
3+
=== contextualTypingGenericFunction2.ts ===
4+
// https://github.com/microsoft/TypeScript/issues/61791
5+
6+
declare const fn1: <T, Args extends Array<any>, Ret>(
7+
>fn1 : Symbol(fn1, Decl(contextualTypingGenericFunction2.ts, 2, 13))
8+
>T : Symbol(T, Decl(contextualTypingGenericFunction2.ts, 2, 20))
9+
>Args : Symbol(Args, Decl(contextualTypingGenericFunction2.ts, 2, 22))
10+
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 4 more)
11+
>Ret : Symbol(Ret, Decl(contextualTypingGenericFunction2.ts, 2, 47))
12+
13+
self: T,
14+
>self : Symbol(self, Decl(contextualTypingGenericFunction2.ts, 2, 53))
15+
>T : Symbol(T, Decl(contextualTypingGenericFunction2.ts, 2, 20))
16+
17+
body: (this: T, ...args: Args) => Ret,
18+
>body : Symbol(body, Decl(contextualTypingGenericFunction2.ts, 3, 10))
19+
>this : Symbol(this, Decl(contextualTypingGenericFunction2.ts, 4, 9))
20+
>T : Symbol(T, Decl(contextualTypingGenericFunction2.ts, 2, 20))
21+
>args : Symbol(args, Decl(contextualTypingGenericFunction2.ts, 4, 17))
22+
>Args : Symbol(Args, Decl(contextualTypingGenericFunction2.ts, 2, 22))
23+
>Ret : Symbol(Ret, Decl(contextualTypingGenericFunction2.ts, 2, 47))
24+
25+
) => (...args: Args) => Ret;
26+
>args : Symbol(args, Decl(contextualTypingGenericFunction2.ts, 5, 6))
27+
>Args : Symbol(Args, Decl(contextualTypingGenericFunction2.ts, 2, 22))
28+
>Ret : Symbol(Ret, Decl(contextualTypingGenericFunction2.ts, 2, 47))
29+
30+
export const ok1 = fn1({ message: "foo" }, function (n: number) {
31+
>ok1 : Symbol(ok1, Decl(contextualTypingGenericFunction2.ts, 7, 12))
32+
>fn1 : Symbol(fn1, Decl(contextualTypingGenericFunction2.ts, 2, 13))
33+
>message : Symbol(message, Decl(contextualTypingGenericFunction2.ts, 7, 24))
34+
>n : Symbol(n, Decl(contextualTypingGenericFunction2.ts, 7, 53))
35+
36+
this.message;
37+
>this.message : Symbol(message, Decl(contextualTypingGenericFunction2.ts, 7, 24))
38+
>this : Symbol(this, Decl(contextualTypingGenericFunction2.ts, 4, 9))
39+
>message : Symbol(message, Decl(contextualTypingGenericFunction2.ts, 7, 24))
40+
41+
});
42+
43+
export const ok2 = fn1({ message: "foo" }, function <N>(n: N) {
44+
>ok2 : Symbol(ok2, Decl(contextualTypingGenericFunction2.ts, 11, 12))
45+
>fn1 : Symbol(fn1, Decl(contextualTypingGenericFunction2.ts, 2, 13))
46+
>message : Symbol(message, Decl(contextualTypingGenericFunction2.ts, 11, 24))
47+
>N : Symbol(N, Decl(contextualTypingGenericFunction2.ts, 11, 53))
48+
>n : Symbol(n, Decl(contextualTypingGenericFunction2.ts, 11, 56))
49+
>N : Symbol(N, Decl(contextualTypingGenericFunction2.ts, 11, 53))
50+
51+
this.message;
52+
>this.message : Symbol(message, Decl(contextualTypingGenericFunction2.ts, 11, 24))
53+
>this : Symbol(this, Decl(contextualTypingGenericFunction2.ts, 4, 9))
54+
>message : Symbol(message, Decl(contextualTypingGenericFunction2.ts, 11, 24))
55+
56+
});
57+
58+
declare const fn2: <Args extends Array<any>, Ret>(
59+
>fn2 : Symbol(fn2, Decl(contextualTypingGenericFunction2.ts, 15, 13))
60+
>Args : Symbol(Args, Decl(contextualTypingGenericFunction2.ts, 15, 20))
61+
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 4 more)
62+
>Ret : Symbol(Ret, Decl(contextualTypingGenericFunction2.ts, 15, 44))
63+
64+
body: (first: string, ...args: Args) => Ret,
65+
>body : Symbol(body, Decl(contextualTypingGenericFunction2.ts, 15, 50))
66+
>first : Symbol(first, Decl(contextualTypingGenericFunction2.ts, 16, 9))
67+
>args : Symbol(args, Decl(contextualTypingGenericFunction2.ts, 16, 23))
68+
>Args : Symbol(Args, Decl(contextualTypingGenericFunction2.ts, 15, 20))
69+
>Ret : Symbol(Ret, Decl(contextualTypingGenericFunction2.ts, 15, 44))
70+
71+
) => (...args: Args) => Ret;
72+
>args : Symbol(args, Decl(contextualTypingGenericFunction2.ts, 17, 6))
73+
>Args : Symbol(Args, Decl(contextualTypingGenericFunction2.ts, 15, 20))
74+
>Ret : Symbol(Ret, Decl(contextualTypingGenericFunction2.ts, 15, 44))
75+
76+
export const ok3 = fn2(function <N>(first, n: N) {});
77+
>ok3 : Symbol(ok3, Decl(contextualTypingGenericFunction2.ts, 19, 12))
78+
>fn2 : Symbol(fn2, Decl(contextualTypingGenericFunction2.ts, 15, 13))
79+
>N : Symbol(N, Decl(contextualTypingGenericFunction2.ts, 19, 33))
80+
>first : Symbol(first, Decl(contextualTypingGenericFunction2.ts, 19, 36))
81+
>n : Symbol(n, Decl(contextualTypingGenericFunction2.ts, 19, 42))
82+
>N : Symbol(N, Decl(contextualTypingGenericFunction2.ts, 19, 33))
83+
84+
declare const fn3: <Args extends Array<any>, Ret>(
85+
>fn3 : Symbol(fn3, Decl(contextualTypingGenericFunction2.ts, 21, 13))
86+
>Args : Symbol(Args, Decl(contextualTypingGenericFunction2.ts, 21, 20))
87+
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 4 more)
88+
>Ret : Symbol(Ret, Decl(contextualTypingGenericFunction2.ts, 21, 44))
89+
90+
body: (...args: Args) => (arg: string) => Ret,
91+
>body : Symbol(body, Decl(contextualTypingGenericFunction2.ts, 21, 50))
92+
>args : Symbol(args, Decl(contextualTypingGenericFunction2.ts, 22, 9))
93+
>Args : Symbol(Args, Decl(contextualTypingGenericFunction2.ts, 21, 20))
94+
>arg : Symbol(arg, Decl(contextualTypingGenericFunction2.ts, 22, 28))
95+
>Ret : Symbol(Ret, Decl(contextualTypingGenericFunction2.ts, 21, 44))
96+
97+
) => (...args: Args) => Ret;
98+
>args : Symbol(args, Decl(contextualTypingGenericFunction2.ts, 23, 6))
99+
>Args : Symbol(Args, Decl(contextualTypingGenericFunction2.ts, 21, 20))
100+
>Ret : Symbol(Ret, Decl(contextualTypingGenericFunction2.ts, 21, 44))
101+
102+
export const ok4 = fn3(function <N>(n: N) {
103+
>ok4 : Symbol(ok4, Decl(contextualTypingGenericFunction2.ts, 25, 12))
104+
>fn3 : Symbol(fn3, Decl(contextualTypingGenericFunction2.ts, 21, 13))
105+
>N : Symbol(N, Decl(contextualTypingGenericFunction2.ts, 25, 33))
106+
>n : Symbol(n, Decl(contextualTypingGenericFunction2.ts, 25, 36))
107+
>N : Symbol(N, Decl(contextualTypingGenericFunction2.ts, 25, 33))
108+
109+
return (arg) => {
110+
>arg : Symbol(arg, Decl(contextualTypingGenericFunction2.ts, 26, 12))
111+
112+
return 10
113+
}
114+
});
115+
116+
declare function fn4<T, P>(config: {
117+
>fn4 : Symbol(fn4, Decl(contextualTypingGenericFunction2.ts, 29, 3))
118+
>T : Symbol(T, Decl(contextualTypingGenericFunction2.ts, 31, 21))
119+
>P : Symbol(P, Decl(contextualTypingGenericFunction2.ts, 31, 23))
120+
>config : Symbol(config, Decl(contextualTypingGenericFunction2.ts, 31, 27))
121+
122+
context: T;
123+
>context : Symbol(context, Decl(contextualTypingGenericFunction2.ts, 31, 36))
124+
>T : Symbol(T, Decl(contextualTypingGenericFunction2.ts, 31, 21))
125+
126+
callback: (params: P) => (context: T, params: P) => number;
127+
>callback : Symbol(callback, Decl(contextualTypingGenericFunction2.ts, 32, 13))
128+
>params : Symbol(params, Decl(contextualTypingGenericFunction2.ts, 33, 13))
129+
>P : Symbol(P, Decl(contextualTypingGenericFunction2.ts, 31, 23))
130+
>context : Symbol(context, Decl(contextualTypingGenericFunction2.ts, 33, 28))
131+
>T : Symbol(T, Decl(contextualTypingGenericFunction2.ts, 31, 21))
132+
>params : Symbol(params, Decl(contextualTypingGenericFunction2.ts, 33, 39))
133+
>P : Symbol(P, Decl(contextualTypingGenericFunction2.ts, 31, 23))
134+
135+
}): (params: P) => number;
136+
>params : Symbol(params, Decl(contextualTypingGenericFunction2.ts, 34, 5))
137+
>P : Symbol(P, Decl(contextualTypingGenericFunction2.ts, 31, 23))
138+
139+
export const ok5 = fn4({
140+
>ok5 : Symbol(ok5, Decl(contextualTypingGenericFunction2.ts, 36, 12))
141+
>fn4 : Symbol(fn4, Decl(contextualTypingGenericFunction2.ts, 29, 3))
142+
143+
context: 1,
144+
>context : Symbol(context, Decl(contextualTypingGenericFunction2.ts, 36, 24))
145+
146+
callback: <T,>(params: T) => {
147+
>callback : Symbol(callback, Decl(contextualTypingGenericFunction2.ts, 37, 13))
148+
>T : Symbol(T, Decl(contextualTypingGenericFunction2.ts, 38, 13))
149+
>params : Symbol(params, Decl(contextualTypingGenericFunction2.ts, 38, 17))
150+
>T : Symbol(T, Decl(contextualTypingGenericFunction2.ts, 38, 13))
151+
152+
return (a, b) => a + 1;
153+
>a : Symbol(a, Decl(contextualTypingGenericFunction2.ts, 39, 12))
154+
>b : Symbol(b, Decl(contextualTypingGenericFunction2.ts, 39, 14))
155+
>a : Symbol(a, Decl(contextualTypingGenericFunction2.ts, 39, 12))
156+
157+
},
158+
});
159+
160+
declare const fnGen1: <T, Args extends Array<any>, Ret>(
161+
>fnGen1 : Symbol(fnGen1, Decl(contextualTypingGenericFunction2.ts, 43, 13))
162+
>T : Symbol(T, Decl(contextualTypingGenericFunction2.ts, 43, 23))
163+
>Args : Symbol(Args, Decl(contextualTypingGenericFunction2.ts, 43, 25))
164+
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 4 more)
165+
>Ret : Symbol(Ret, Decl(contextualTypingGenericFunction2.ts, 43, 50))
166+
167+
self: T,
168+
>self : Symbol(self, Decl(contextualTypingGenericFunction2.ts, 43, 56))
169+
>T : Symbol(T, Decl(contextualTypingGenericFunction2.ts, 43, 23))
170+
171+
body: (this: T, ...args: Args) => Generator<any, Ret, never>,
172+
>body : Symbol(body, Decl(contextualTypingGenericFunction2.ts, 44, 10))
173+
>this : Symbol(this, Decl(contextualTypingGenericFunction2.ts, 45, 9))
174+
>T : Symbol(T, Decl(contextualTypingGenericFunction2.ts, 43, 23))
175+
>args : Symbol(args, Decl(contextualTypingGenericFunction2.ts, 45, 17))
176+
>Args : Symbol(Args, Decl(contextualTypingGenericFunction2.ts, 43, 25))
177+
>Generator : Symbol(Generator, Decl(lib.es2015.generator.d.ts, --, --))
178+
>Ret : Symbol(Ret, Decl(contextualTypingGenericFunction2.ts, 43, 50))
179+
180+
) => (...args: Args) => Ret;
181+
>args : Symbol(args, Decl(contextualTypingGenericFunction2.ts, 46, 6))
182+
>Args : Symbol(Args, Decl(contextualTypingGenericFunction2.ts, 43, 25))
183+
>Ret : Symbol(Ret, Decl(contextualTypingGenericFunction2.ts, 43, 50))
184+
185+
export const ok6 = fnGen1({ message: "foo" }, function* (n: number) {
186+
>ok6 : Symbol(ok6, Decl(contextualTypingGenericFunction2.ts, 48, 12))
187+
>fnGen1 : Symbol(fnGen1, Decl(contextualTypingGenericFunction2.ts, 43, 13))
188+
>message : Symbol(message, Decl(contextualTypingGenericFunction2.ts, 48, 27))
189+
>n : Symbol(n, Decl(contextualTypingGenericFunction2.ts, 48, 57))
190+
191+
this.message;
192+
>this.message : Symbol(message, Decl(contextualTypingGenericFunction2.ts, 48, 27))
193+
>this : Symbol(this, Decl(contextualTypingGenericFunction2.ts, 45, 9))
194+
>message : Symbol(message, Decl(contextualTypingGenericFunction2.ts, 48, 27))
195+
196+
});
197+
198+
export const ok7 = fnGen1({ message: "foo" }, function* <N>(n: N) {
199+
>ok7 : Symbol(ok7, Decl(contextualTypingGenericFunction2.ts, 52, 12))
200+
>fnGen1 : Symbol(fnGen1, Decl(contextualTypingGenericFunction2.ts, 43, 13))
201+
>message : Symbol(message, Decl(contextualTypingGenericFunction2.ts, 52, 27))
202+
>N : Symbol(N, Decl(contextualTypingGenericFunction2.ts, 52, 57))
203+
>n : Symbol(n, Decl(contextualTypingGenericFunction2.ts, 52, 60))
204+
>N : Symbol(N, Decl(contextualTypingGenericFunction2.ts, 52, 57))
205+
206+
this.message;
207+
>this.message : Symbol(message, Decl(contextualTypingGenericFunction2.ts, 52, 27))
208+
>this : Symbol(this, Decl(contextualTypingGenericFunction2.ts, 45, 9))
209+
>message : Symbol(message, Decl(contextualTypingGenericFunction2.ts, 52, 27))
210+
211+
});
212+

0 commit comments

Comments
 (0)