Skip to content

Commit 83640c0

Browse files
committed
Report a semantic error for an arrow function with a "this" parameter.
Fixes microsoft#9744.
1 parent 93722c8 commit 83640c0

8 files changed

+203
-2
lines changed

src/compiler/checker.ts

+3
Original file line numberDiff line numberDiff line change
@@ -21857,6 +21857,9 @@ namespace ts {
2185721857
if (func.kind === SyntaxKind.Constructor || func.kind === SyntaxKind.ConstructSignature || func.kind === SyntaxKind.ConstructorType) {
2185821858
error(node, Diagnostics.A_constructor_cannot_have_a_this_parameter);
2185921859
}
21860+
if (func.kind === SyntaxKind.ArrowFunction) {
21861+
error(node, Diagnostics.An_arrow_function_cannot_have_a_this_parameter);
21862+
}
2186021863
}
2186121864

2186221865
// Only check rest parameter type if it's not a binding pattern. Since binding patterns are

src/compiler/diagnosticMessages.json

+4
Original file line numberDiff line numberDiff line change
@@ -2417,6 +2417,10 @@
24172417
"category": "Error",
24182418
"code": 2729
24192419
},
2420+
"An arrow function cannot have a 'this' parameter.": {
2421+
"category": "Error",
2422+
"code": 2730
2423+
},
24202424

24212425
"Import declaration '{0}' is using private name '{1}'.": {
24222426
"category": "Error",

src/compiler/parser.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -3537,8 +3537,9 @@ namespace ts {
35373537
}
35383538

35393539
// If we had "(" followed by something that's not an identifier,
3540-
// then this definitely doesn't look like a lambda.
3541-
if (!isIdentifier()) {
3540+
// then this definitely doesn't look like a lambda. "this" is not
3541+
// valid, but we want to parse it and then give a semantic error.
3542+
if (!isIdentifier() && second !== SyntaxKind.ThisKeyword) {
35423543
return Tristate.False;
35433544
}
35443545

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
tests/cases/compiler/arrowFunctionWithThisParameter.ts(2,15): error TS2730: An arrow function cannot have a 'this' parameter.
2+
tests/cases/compiler/arrowFunctionWithThisParameter.ts(4,20): error TS2331: 'this' cannot be referenced in a module or namespace body.
3+
tests/cases/compiler/arrowFunctionWithThisParameter.ts(6,18): error TS2730: An arrow function cannot have a 'this' parameter.
4+
tests/cases/compiler/arrowFunctionWithThisParameter.ts(7,20): error TS2331: 'this' cannot be referenced in a module or namespace body.
5+
tests/cases/compiler/arrowFunctionWithThisParameter.ts(9,21): error TS2730: An arrow function cannot have a 'this' parameter.
6+
tests/cases/compiler/arrowFunctionWithThisParameter.ts(10,20): error TS2331: 'this' cannot be referenced in a module or namespace body.
7+
tests/cases/compiler/arrowFunctionWithThisParameter.ts(12,24): error TS2730: An arrow function cannot have a 'this' parameter.
8+
tests/cases/compiler/arrowFunctionWithThisParameter.ts(13,20): error TS2331: 'this' cannot be referenced in a module or namespace body.
9+
10+
11+
==== tests/cases/compiler/arrowFunctionWithThisParameter.ts (8 errors) ====
12+
namespace CannotReferenceThisInHere {
13+
let f1 = (this: number) => {
14+
~~~~~~~~~~~~
15+
!!! error TS2730: An arrow function cannot have a 'this' parameter.
16+
// Test that the erroneously specified "this" type is not being used.
17+
let that = this;
18+
~~~~
19+
!!! error TS2331: 'this' cannot be referenced in a module or namespace body.
20+
};
21+
let f2 = <T>(this: number) => {
22+
~~~~~~~~~~~~
23+
!!! error TS2730: An arrow function cannot have a 'this' parameter.
24+
let that = this;
25+
~~~~
26+
!!! error TS2331: 'this' cannot be referenced in a module or namespace body.
27+
};
28+
let f3 = async (this: number) => {
29+
~~~~~~~~~~~~
30+
!!! error TS2730: An arrow function cannot have a 'this' parameter.
31+
let that = this;
32+
~~~~
33+
!!! error TS2331: 'this' cannot be referenced in a module or namespace body.
34+
};
35+
let f4 = async <T>(this: number) => {
36+
~~~~~~~~~~~~
37+
!!! error TS2730: An arrow function cannot have a 'this' parameter.
38+
let that = this;
39+
~~~~
40+
!!! error TS2331: 'this' cannot be referenced in a module or namespace body.
41+
};
42+
}
43+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
//// [arrowFunctionWithThisParameter.ts]
2+
namespace CannotReferenceThisInHere {
3+
let f1 = (this: number) => {
4+
// Test that the erroneously specified "this" type is not being used.
5+
let that = this;
6+
};
7+
let f2 = <T>(this: number) => {
8+
let that = this;
9+
};
10+
let f3 = async (this: number) => {
11+
let that = this;
12+
};
13+
let f4 = async <T>(this: number) => {
14+
let that = this;
15+
};
16+
}
17+
18+
19+
//// [arrowFunctionWithThisParameter.js]
20+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
21+
return new (P || (P = Promise))(function (resolve, reject) {
22+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
23+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
24+
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
25+
step((generator = generator.apply(thisArg, _arguments || [])).next());
26+
});
27+
};
28+
var CannotReferenceThisInHere;
29+
(function (CannotReferenceThisInHere) {
30+
let f1 = () => {
31+
// Test that the erroneously specified "this" type is not being used.
32+
let that = this;
33+
};
34+
let f2 = () => {
35+
let that = this;
36+
};
37+
let f3 = () => __awaiter(this, void 0, void 0, function* () {
38+
let that = this;
39+
});
40+
let f4 = () => __awaiter(this, void 0, void 0, function* () {
41+
let that = this;
42+
});
43+
})(CannotReferenceThisInHere || (CannotReferenceThisInHere = {}));
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
=== tests/cases/compiler/arrowFunctionWithThisParameter.ts ===
2+
namespace CannotReferenceThisInHere {
3+
>CannotReferenceThisInHere : Symbol(CannotReferenceThisInHere, Decl(arrowFunctionWithThisParameter.ts, 0, 0))
4+
5+
let f1 = (this: number) => {
6+
>f1 : Symbol(f1, Decl(arrowFunctionWithThisParameter.ts, 1, 7))
7+
>this : Symbol(this, Decl(arrowFunctionWithThisParameter.ts, 1, 14))
8+
9+
// Test that the erroneously specified "this" type is not being used.
10+
let that = this;
11+
>that : Symbol(that, Decl(arrowFunctionWithThisParameter.ts, 3, 11))
12+
13+
};
14+
let f2 = <T>(this: number) => {
15+
>f2 : Symbol(f2, Decl(arrowFunctionWithThisParameter.ts, 5, 7))
16+
>T : Symbol(T, Decl(arrowFunctionWithThisParameter.ts, 5, 14))
17+
>this : Symbol(this, Decl(arrowFunctionWithThisParameter.ts, 5, 17))
18+
19+
let that = this;
20+
>that : Symbol(that, Decl(arrowFunctionWithThisParameter.ts, 6, 11))
21+
22+
};
23+
let f3 = async (this: number) => {
24+
>f3 : Symbol(f3, Decl(arrowFunctionWithThisParameter.ts, 8, 7))
25+
>this : Symbol(this, Decl(arrowFunctionWithThisParameter.ts, 8, 20))
26+
27+
let that = this;
28+
>that : Symbol(that, Decl(arrowFunctionWithThisParameter.ts, 9, 11))
29+
30+
};
31+
let f4 = async <T>(this: number) => {
32+
>f4 : Symbol(f4, Decl(arrowFunctionWithThisParameter.ts, 11, 7))
33+
>T : Symbol(T, Decl(arrowFunctionWithThisParameter.ts, 11, 20))
34+
>this : Symbol(this, Decl(arrowFunctionWithThisParameter.ts, 11, 23))
35+
36+
let that = this;
37+
>that : Symbol(that, Decl(arrowFunctionWithThisParameter.ts, 12, 11))
38+
39+
};
40+
}
41+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
=== tests/cases/compiler/arrowFunctionWithThisParameter.ts ===
2+
namespace CannotReferenceThisInHere {
3+
>CannotReferenceThisInHere : typeof CannotReferenceThisInHere
4+
5+
let f1 = (this: number) => {
6+
>f1 : (this: number) => void
7+
>(this: number) => { // Test that the erroneously specified "this" type is not being used. let that = this; } : (this: number) => void
8+
>this : number
9+
10+
// Test that the erroneously specified "this" type is not being used.
11+
let that = this;
12+
>that : any
13+
>this : any
14+
15+
};
16+
let f2 = <T>(this: number) => {
17+
>f2 : <T>(this: number) => void
18+
><T>(this: number) => { let that = this; } : <T>(this: number) => void
19+
>T : T
20+
>this : number
21+
22+
let that = this;
23+
>that : any
24+
>this : any
25+
26+
};
27+
let f3 = async (this: number) => {
28+
>f3 : (this: number) => Promise<void>
29+
>async (this: number) => { let that = this; } : (this: number) => Promise<void>
30+
>this : number
31+
32+
let that = this;
33+
>that : any
34+
>this : any
35+
36+
};
37+
let f4 = async <T>(this: number) => {
38+
>f4 : <T>(this: number) => Promise<void>
39+
>async <T>(this: number) => { let that = this; } : <T>(this: number) => Promise<void>
40+
>T : T
41+
>this : number
42+
43+
let that = this;
44+
>that : any
45+
>this : any
46+
47+
};
48+
}
49+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// @target: es6
2+
3+
namespace CannotReferenceThisInHere {
4+
let f1 = (this: number) => {
5+
// Test that the erroneously specified "this" type is not being used.
6+
let that = this;
7+
};
8+
let f2 = <T>(this: number) => {
9+
let that = this;
10+
};
11+
let f3 = async (this: number) => {
12+
let that = this;
13+
};
14+
let f4 = async <T>(this: number) => {
15+
let that = this;
16+
};
17+
}

0 commit comments

Comments
 (0)