Skip to content

Commit aa38cdb

Browse files
committed
Contextually type IIFE params by their arguments
1 parent 673fa41 commit aa38cdb

File tree

5 files changed

+436
-3
lines changed

5 files changed

+436
-3
lines changed

src/compiler/checker.ts

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8520,6 +8520,17 @@ namespace ts {
85208520
function getContextuallyTypedParameterType(parameter: ParameterDeclaration): Type {
85218521
const func = parameter.parent;
85228522
if (isContextSensitiveFunctionOrObjectLiteralMethod(func)) {
8523+
if (isIife(func)) {
8524+
const indexOfParameter = indexOf(func.parameters, parameter);
8525+
const call = func.parent.parent as CallExpression;
8526+
if (indexOfParameter < call.arguments.length) {
8527+
const type = getTypeOfExpression(call.arguments[indexOfParameter]);
8528+
if (type && parameter.dotDotDotToken) {
8529+
return createArrayType(type);
8530+
}
8531+
return type;
8532+
}
8533+
}
85238534
const contextualSignature = getContextualSignature(func);
85248535
if (contextualSignature) {
85258536
const funcHasRestParameters = hasRestParameter(func);
@@ -8540,6 +8551,13 @@ namespace ts {
85408551
return undefined;
85418552
}
85428553

8554+
function isIife(func: FunctionExpression | MethodDeclaration) {
8555+
return (func.kind === SyntaxKind.FunctionExpression || func.kind === SyntaxKind.ArrowFunction) &&
8556+
func.parent.kind === SyntaxKind.ParenthesizedExpression &&
8557+
func.parent.parent.kind === SyntaxKind.CallExpression &&
8558+
(func.parent.parent as CallExpression).expression === func.parent;
8559+
}
8560+
85438561
// In a variable, parameter or property declaration with a type annotation,
85448562
// the contextual type of an initializer expression is the type of the variable, parameter or property.
85458563
// Otherwise, in a parameter declaration of a contextually typed function expression,
@@ -8898,9 +8916,9 @@ namespace ts {
88988916
}
88998917

89008918
function getContextualTypeForFunctionLikeDeclaration(node: FunctionExpression | MethodDeclaration) {
8901-
return isObjectLiteralMethod(node)
8902-
? getContextualTypeForObjectLiteralMethod(node)
8903-
: getApparentTypeOfContextualType(node);
8919+
return isObjectLiteralMethod(node) ?
8920+
getContextualTypeForObjectLiteralMethod(node) :
8921+
getApparentTypeOfContextualType(node);
89048922
}
89058923

89068924
// Return the contextual signature for a given expression node. A contextual type provides a
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
//// [contextuallyTypedIife.ts]
2+
// arrow
3+
(jake => { })("build");
4+
// function expression
5+
(function (cats) { })("lol");
6+
// multiple arguments
7+
((a, b, c) => { })("foo", 101, false);
8+
// contextually typed parameters.
9+
(f => f(1))(i => i + 1);
10+
// default parameters
11+
((m = 10) => m + 1)(12);
12+
((n = 10) => n + 1)();
13+
// optional parameters
14+
((j?) => j + 1)(12);
15+
((k?) => k + 1)();
16+
((l, o?) => l + o)(12); // o should be any
17+
// rest parameters
18+
((...numbers) => numbers.every(n => n > 0))(5,6,7);
19+
((...noNumbers) => noNumbers.some(n => n > 0))();
20+
((first, ...rest) => first ? [] : rest.map(n => n > 0))(8,9,10);
21+
// destructuring parameters (with defaults too!)
22+
(({ q }) => q)({ q : 13 });
23+
(({ p = 14 }) => p)({ p : 15 });
24+
(({ r = 17 } = { r: 18 }) => r)({r : 19});
25+
(({ u = 22 } = { u: 23 }) => u)();
26+
27+
28+
29+
30+
//// [contextuallyTypedIife.js]
31+
// arrow
32+
(function (jake) { })("build");
33+
// function expression
34+
(function (cats) { })("lol");
35+
// multiple arguments
36+
(function (a, b, c) { })("foo", 101, false);
37+
// contextually typed parameters.
38+
(function (f) { return f(1); })(function (i) { return i + 1; });
39+
// default parameters
40+
(function (m) {
41+
if (m === void 0) { m = 10; }
42+
return m + 1;
43+
})(12);
44+
(function (n) {
45+
if (n === void 0) { n = 10; }
46+
return n + 1;
47+
})();
48+
// optional parameters
49+
(function (j) { return j + 1; })(12);
50+
(function (k) { return k + 1; })();
51+
(function (l, o) { return l + o; })(12); // o should be any
52+
// rest parameters
53+
(function () {
54+
var numbers = [];
55+
for (var _i = 0; _i < arguments.length; _i++) {
56+
numbers[_i - 0] = arguments[_i];
57+
}
58+
return numbers.every(function (n) { return n > 0; });
59+
})(5, 6, 7);
60+
(function () {
61+
var noNumbers = [];
62+
for (var _i = 0; _i < arguments.length; _i++) {
63+
noNumbers[_i - 0] = arguments[_i];
64+
}
65+
return noNumbers.some(function (n) { return n > 0; });
66+
})();
67+
(function (first) {
68+
var rest = [];
69+
for (var _i = 1; _i < arguments.length; _i++) {
70+
rest[_i - 1] = arguments[_i];
71+
}
72+
return first ? [] : rest.map(function (n) { return n > 0; });
73+
})(8, 9, 10);
74+
// destructuring parameters (with defaults too!)
75+
(function (_a) {
76+
var q = _a.q;
77+
return q;
78+
})({ q: 13 });
79+
(function (_a) {
80+
var _b = _a.p, p = _b === void 0 ? 14 : _b;
81+
return p;
82+
})({ p: 15 });
83+
(function (_a) {
84+
var _b = (_a === void 0 ? { r: 18 } : _a).r, r = _b === void 0 ? 17 : _b;
85+
return r;
86+
})({ r: 19 });
87+
(function (_a) {
88+
var _b = (_a === void 0 ? { u: 23 } : _a).u, u = _b === void 0 ? 22 : _b;
89+
return u;
90+
})();
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
=== tests/cases/conformance/expressions/functions/contextuallyTypedIife.ts ===
2+
// arrow
3+
(jake => { })("build");
4+
>jake : Symbol(jake, Decl(contextuallyTypedIife.ts, 1, 1))
5+
6+
// function expression
7+
(function (cats) { })("lol");
8+
>cats : Symbol(cats, Decl(contextuallyTypedIife.ts, 3, 11))
9+
10+
// multiple arguments
11+
((a, b, c) => { })("foo", 101, false);
12+
>a : Symbol(a, Decl(contextuallyTypedIife.ts, 5, 2))
13+
>b : Symbol(b, Decl(contextuallyTypedIife.ts, 5, 4))
14+
>c : Symbol(c, Decl(contextuallyTypedIife.ts, 5, 7))
15+
16+
// contextually typed parameters.
17+
(f => f(1))(i => i + 1);
18+
>f : Symbol(f, Decl(contextuallyTypedIife.ts, 7, 1))
19+
>f : Symbol(f, Decl(contextuallyTypedIife.ts, 7, 1))
20+
>i : Symbol(i, Decl(contextuallyTypedIife.ts, 7, 12))
21+
>i : Symbol(i, Decl(contextuallyTypedIife.ts, 7, 12))
22+
23+
// default parameters
24+
((m = 10) => m + 1)(12);
25+
>m : Symbol(m, Decl(contextuallyTypedIife.ts, 9, 2))
26+
>m : Symbol(m, Decl(contextuallyTypedIife.ts, 9, 2))
27+
28+
((n = 10) => n + 1)();
29+
>n : Symbol(n, Decl(contextuallyTypedIife.ts, 10, 2))
30+
>n : Symbol(n, Decl(contextuallyTypedIife.ts, 10, 2))
31+
32+
// optional parameters
33+
((j?) => j + 1)(12);
34+
>j : Symbol(j, Decl(contextuallyTypedIife.ts, 12, 2))
35+
>j : Symbol(j, Decl(contextuallyTypedIife.ts, 12, 2))
36+
37+
((k?) => k + 1)();
38+
>k : Symbol(k, Decl(contextuallyTypedIife.ts, 13, 2))
39+
>k : Symbol(k, Decl(contextuallyTypedIife.ts, 13, 2))
40+
41+
((l, o?) => l + o)(12); // o should be any
42+
>l : Symbol(l, Decl(contextuallyTypedIife.ts, 14, 2))
43+
>o : Symbol(o, Decl(contextuallyTypedIife.ts, 14, 4))
44+
>l : Symbol(l, Decl(contextuallyTypedIife.ts, 14, 2))
45+
>o : Symbol(o, Decl(contextuallyTypedIife.ts, 14, 4))
46+
47+
// rest parameters
48+
((...numbers) => numbers.every(n => n > 0))(5,6,7);
49+
>numbers : Symbol(numbers, Decl(contextuallyTypedIife.ts, 16, 2))
50+
>numbers.every : Symbol(Array.every, Decl(lib.d.ts, --, --))
51+
>numbers : Symbol(numbers, Decl(contextuallyTypedIife.ts, 16, 2))
52+
>every : Symbol(Array.every, Decl(lib.d.ts, --, --))
53+
>n : Symbol(n, Decl(contextuallyTypedIife.ts, 16, 31))
54+
>n : Symbol(n, Decl(contextuallyTypedIife.ts, 16, 31))
55+
56+
((...noNumbers) => noNumbers.some(n => n > 0))();
57+
>noNumbers : Symbol(noNumbers, Decl(contextuallyTypedIife.ts, 17, 2))
58+
>noNumbers.some : Symbol(Array.some, Decl(lib.d.ts, --, --))
59+
>noNumbers : Symbol(noNumbers, Decl(contextuallyTypedIife.ts, 17, 2))
60+
>some : Symbol(Array.some, Decl(lib.d.ts, --, --))
61+
>n : Symbol(n, Decl(contextuallyTypedIife.ts, 17, 34))
62+
>n : Symbol(n, Decl(contextuallyTypedIife.ts, 17, 34))
63+
64+
((first, ...rest) => first ? [] : rest.map(n => n > 0))(8,9,10);
65+
>first : Symbol(first, Decl(contextuallyTypedIife.ts, 18, 2))
66+
>rest : Symbol(rest, Decl(contextuallyTypedIife.ts, 18, 8))
67+
>first : Symbol(first, Decl(contextuallyTypedIife.ts, 18, 2))
68+
>rest.map : Symbol(Array.map, Decl(lib.d.ts, --, --))
69+
>rest : Symbol(rest, Decl(contextuallyTypedIife.ts, 18, 8))
70+
>map : Symbol(Array.map, Decl(lib.d.ts, --, --))
71+
>n : Symbol(n, Decl(contextuallyTypedIife.ts, 18, 43))
72+
>n : Symbol(n, Decl(contextuallyTypedIife.ts, 18, 43))
73+
74+
// destructuring parameters (with defaults too!)
75+
(({ q }) => q)({ q : 13 });
76+
>q : Symbol(q, Decl(contextuallyTypedIife.ts, 20, 3))
77+
>q : Symbol(q, Decl(contextuallyTypedIife.ts, 20, 3))
78+
>q : Symbol(q, Decl(contextuallyTypedIife.ts, 20, 16))
79+
80+
(({ p = 14 }) => p)({ p : 15 });
81+
>p : Symbol(p, Decl(contextuallyTypedIife.ts, 21, 3))
82+
>p : Symbol(p, Decl(contextuallyTypedIife.ts, 21, 3))
83+
>p : Symbol(p, Decl(contextuallyTypedIife.ts, 21, 21))
84+
85+
(({ r = 17 } = { r: 18 }) => r)({r : 19});
86+
>r : Symbol(r, Decl(contextuallyTypedIife.ts, 22, 3))
87+
>r : Symbol(r, Decl(contextuallyTypedIife.ts, 22, 16))
88+
>r : Symbol(r, Decl(contextuallyTypedIife.ts, 22, 3))
89+
>r : Symbol(r, Decl(contextuallyTypedIife.ts, 22, 33))
90+
91+
(({ u = 22 } = { u: 23 }) => u)();
92+
>u : Symbol(u, Decl(contextuallyTypedIife.ts, 23, 3))
93+
>u : Symbol(u, Decl(contextuallyTypedIife.ts, 23, 16))
94+
>u : Symbol(u, Decl(contextuallyTypedIife.ts, 23, 3))
95+
96+
97+

0 commit comments

Comments
 (0)