Skip to content

Commit bc6d6ea

Browse files
committed
Merge pull request #8483 from Microsoft/contextually-type-iife-parameters
Contextually type IIFE params by their arguments
2 parents d11ee08 + 96d3db2 commit bc6d6ea

File tree

5 files changed

+537
-3
lines changed

5 files changed

+537
-3
lines changed

src/compiler/checker.ts

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8539,6 +8539,20 @@ namespace ts {
85398539
function getContextuallyTypedParameterType(parameter: ParameterDeclaration): Type {
85408540
const func = parameter.parent;
85418541
if (isContextSensitiveFunctionOrObjectLiteralMethod(func)) {
8542+
const iife = getImmediatelyInvokedFunctionExpression(func);
8543+
if (iife) {
8544+
const indexOfParameter = indexOf(func.parameters, parameter);
8545+
if (iife.arguments && indexOfParameter < iife.arguments.length) {
8546+
if (parameter.dotDotDotToken) {
8547+
const restTypes: Type[] = [];
8548+
for (let i = indexOfParameter; i < iife.arguments.length; i++) {
8549+
restTypes.push(getTypeOfExpression(iife.arguments[i]));
8550+
}
8551+
return createArrayType(getUnionType(restTypes));
8552+
}
8553+
return checkExpression(iife.arguments[indexOfParameter]);
8554+
}
8555+
}
85428556
const contextualSignature = getContextualSignature(func);
85438557
if (contextualSignature) {
85448558
const funcHasRestParameters = hasRestParameter(func);
@@ -8559,6 +8573,20 @@ namespace ts {
85598573
return undefined;
85608574
}
85618575

8576+
function getImmediatelyInvokedFunctionExpression(func: FunctionExpression | MethodDeclaration) {
8577+
if (isFunctionExpressionOrArrowFunction(func)) {
8578+
let prev: Node = func;
8579+
let parent: Node = func.parent;
8580+
while (parent.kind === SyntaxKind.ParenthesizedExpression) {
8581+
prev = parent;
8582+
parent = parent.parent;
8583+
}
8584+
if (parent.kind === SyntaxKind.CallExpression && (parent as CallExpression).expression === prev) {
8585+
return parent as CallExpression;
8586+
}
8587+
}
8588+
}
8589+
85628590
// In a variable, parameter or property declaration with a type annotation,
85638591
// the contextual type of an initializer expression is the type of the variable, parameter or property.
85648592
// Otherwise, in a parameter declaration of a contextually typed function expression,
@@ -8917,9 +8945,9 @@ namespace ts {
89178945
}
89188946

89198947
function getContextualTypeForFunctionLikeDeclaration(node: FunctionExpression | MethodDeclaration) {
8920-
return isObjectLiteralMethod(node)
8921-
? getContextualTypeForObjectLiteralMethod(node)
8922-
: getApparentTypeOfContextualType(node);
8948+
return isObjectLiteralMethod(node) ?
8949+
getContextualTypeForObjectLiteralMethod(node) :
8950+
getApparentTypeOfContextualType(node);
89238951
}
89248952

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

0 commit comments

Comments
 (0)