Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 36169b4

Browse filesBrowse files
authored
Class fields w/esnext+[[Define]]:no shadow error (microsoft#36405)
* Class fields w/esnext+[[Define]]:no shadow error With useDefineForClassFields: true and ESNext target, initializer expressions for property declarations are evaluated in the scope of the class body and are permitted to reference parameters or local variables of the constructor. This is different from classic Typescript behaviour, with useDefineForClassFields: false. There, initialisers of property declarations are evaluated in the scope of the constructor body. Note that when class fields are accepted in the ECMAScript standard, the target will become that year's ES20xx * add negative test case * Add explanatory comment
1 parent 8da3eff commit 36169b4
Copy full SHA for 36169b4

File tree

Expand file treeCollapse file tree

6 files changed

+254
-2
lines changed
Filter options
Expand file treeCollapse file tree

6 files changed

+254
-2
lines changed

‎src/compiler/checker.ts

Copy file name to clipboardExpand all lines: src/compiler/checker.ts
+3-2Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1822,9 +1822,10 @@ namespace ts {
18221822

18231823
// Perform extra checks only if error reporting was requested
18241824
if (nameNotFoundMessage) {
1825-
if (propertyWithInvalidInitializer) {
1825+
if (propertyWithInvalidInitializer && !(compilerOptions.target === ScriptTarget.ESNext && compilerOptions.useDefineForClassFields)) {
18261826
// We have a match, but the reference occurred within a property initializer and the identifier also binds
1827-
// to a local variable in the constructor where the code will be emitted.
1827+
// to a local variable in the constructor where the code will be emitted. Note that this is actually allowed
1828+
// with ESNext+useDefineForClassFields because the scope semantics are different.
18281829
const propertyName = (<PropertyDeclaration>propertyWithInvalidInitializer).name;
18291830
error(errorLocation, Diagnostics.Initializer_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor,
18301831
declarationNameToString(propertyName), diagnosticName(nameArg!));
+38Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
tests/cases/conformance/classes/propertyMemberDeclarations/constructorParameterShadowsOuterScopes2.ts(28,9): error TS2304: Cannot find name 'z'.
2+
3+
4+
==== tests/cases/conformance/classes/propertyMemberDeclarations/constructorParameterShadowsOuterScopes2.ts (1 errors) ====
5+
// With useDefineForClassFields: true and ESNext target, initializer
6+
// expressions for property declarations are evaluated in the scope of
7+
// the class body and are permitted to reference parameters or local
8+
// variables of the constructor. This is different from classic
9+
// Typescript behaviour, with useDefineForClassFields: false. There,
10+
// initialisers of property declarations are evaluated in the scope of
11+
// the constructor body.
12+
13+
// Note that when class fields are accepted in the ECMAScript
14+
// standard, the target will become that year's ES20xx
15+
16+
var x = 1;
17+
class C {
18+
b = x; // ok
19+
constructor(x: string) {
20+
}
21+
}
22+
23+
var y = 1;
24+
class D {
25+
b = y; // ok
26+
constructor(x: string) {
27+
var y = "";
28+
}
29+
}
30+
31+
class E {
32+
b = z; // not ok
33+
~
34+
!!! error TS2304: Cannot find name 'z'.
35+
constructor(z: string) {
36+
}
37+
}
38+
+62Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
//// [constructorParameterShadowsOuterScopes2.ts]
2+
// With useDefineForClassFields: true and ESNext target, initializer
3+
// expressions for property declarations are evaluated in the scope of
4+
// the class body and are permitted to reference parameters or local
5+
// variables of the constructor. This is different from classic
6+
// Typescript behaviour, with useDefineForClassFields: false. There,
7+
// initialisers of property declarations are evaluated in the scope of
8+
// the constructor body.
9+
10+
// Note that when class fields are accepted in the ECMAScript
11+
// standard, the target will become that year's ES20xx
12+
13+
var x = 1;
14+
class C {
15+
b = x; // ok
16+
constructor(x: string) {
17+
}
18+
}
19+
20+
var y = 1;
21+
class D {
22+
b = y; // ok
23+
constructor(x: string) {
24+
var y = "";
25+
}
26+
}
27+
28+
class E {
29+
b = z; // not ok
30+
constructor(z: string) {
31+
}
32+
}
33+
34+
35+
//// [constructorParameterShadowsOuterScopes2.js]
36+
// With useDefineForClassFields: true and ESNext target, initializer
37+
// expressions for property declarations are evaluated in the scope of
38+
// the class body and are permitted to reference parameters or local
39+
// variables of the constructor. This is different from classic
40+
// Typescript behaviour, with useDefineForClassFields: false. There,
41+
// initialisers of property declarations are evaluated in the scope of
42+
// the constructor body.
43+
// Note that when class fields are accepted in the ECMAScript
44+
// standard, the target will become that year's ES20xx
45+
var x = 1;
46+
class C {
47+
b = x; // ok
48+
constructor(x) {
49+
}
50+
}
51+
var y = 1;
52+
class D {
53+
b = y; // ok
54+
constructor(x) {
55+
var y = "";
56+
}
57+
}
58+
class E {
59+
b = z; // not ok
60+
constructor(z) {
61+
}
62+
}
+56Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
=== tests/cases/conformance/classes/propertyMemberDeclarations/constructorParameterShadowsOuterScopes2.ts ===
2+
// With useDefineForClassFields: true and ESNext target, initializer
3+
// expressions for property declarations are evaluated in the scope of
4+
// the class body and are permitted to reference parameters or local
5+
// variables of the constructor. This is different from classic
6+
// Typescript behaviour, with useDefineForClassFields: false. There,
7+
// initialisers of property declarations are evaluated in the scope of
8+
// the constructor body.
9+
10+
// Note that when class fields are accepted in the ECMAScript
11+
// standard, the target will become that year's ES20xx
12+
13+
var x = 1;
14+
>x : Symbol(x, Decl(constructorParameterShadowsOuterScopes2.ts, 11, 3))
15+
16+
class C {
17+
>C : Symbol(C, Decl(constructorParameterShadowsOuterScopes2.ts, 11, 10))
18+
19+
b = x; // ok
20+
>b : Symbol(C.b, Decl(constructorParameterShadowsOuterScopes2.ts, 12, 9))
21+
>x : Symbol(x, Decl(constructorParameterShadowsOuterScopes2.ts, 11, 3))
22+
23+
constructor(x: string) {
24+
>x : Symbol(x, Decl(constructorParameterShadowsOuterScopes2.ts, 14, 16))
25+
}
26+
}
27+
28+
var y = 1;
29+
>y : Symbol(y, Decl(constructorParameterShadowsOuterScopes2.ts, 18, 3))
30+
31+
class D {
32+
>D : Symbol(D, Decl(constructorParameterShadowsOuterScopes2.ts, 18, 10))
33+
34+
b = y; // ok
35+
>b : Symbol(D.b, Decl(constructorParameterShadowsOuterScopes2.ts, 19, 9))
36+
>y : Symbol(y, Decl(constructorParameterShadowsOuterScopes2.ts, 18, 3))
37+
38+
constructor(x: string) {
39+
>x : Symbol(x, Decl(constructorParameterShadowsOuterScopes2.ts, 21, 16))
40+
41+
var y = "";
42+
>y : Symbol(y, Decl(constructorParameterShadowsOuterScopes2.ts, 22, 11))
43+
}
44+
}
45+
46+
class E {
47+
>E : Symbol(E, Decl(constructorParameterShadowsOuterScopes2.ts, 24, 1))
48+
49+
b = z; // not ok
50+
>b : Symbol(E.b, Decl(constructorParameterShadowsOuterScopes2.ts, 26, 9))
51+
52+
constructor(z: string) {
53+
>z : Symbol(z, Decl(constructorParameterShadowsOuterScopes2.ts, 28, 16))
54+
}
55+
}
56+
+60Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
=== tests/cases/conformance/classes/propertyMemberDeclarations/constructorParameterShadowsOuterScopes2.ts ===
2+
// With useDefineForClassFields: true and ESNext target, initializer
3+
// expressions for property declarations are evaluated in the scope of
4+
// the class body and are permitted to reference parameters or local
5+
// variables of the constructor. This is different from classic
6+
// Typescript behaviour, with useDefineForClassFields: false. There,
7+
// initialisers of property declarations are evaluated in the scope of
8+
// the constructor body.
9+
10+
// Note that when class fields are accepted in the ECMAScript
11+
// standard, the target will become that year's ES20xx
12+
13+
var x = 1;
14+
>x : number
15+
>1 : 1
16+
17+
class C {
18+
>C : C
19+
20+
b = x; // ok
21+
>b : number
22+
>x : number
23+
24+
constructor(x: string) {
25+
>x : string
26+
}
27+
}
28+
29+
var y = 1;
30+
>y : number
31+
>1 : 1
32+
33+
class D {
34+
>D : D
35+
36+
b = y; // ok
37+
>b : number
38+
>y : number
39+
40+
constructor(x: string) {
41+
>x : string
42+
43+
var y = "";
44+
>y : string
45+
>"" : ""
46+
}
47+
}
48+
49+
class E {
50+
>E : E
51+
52+
b = z; // not ok
53+
>b : any
54+
>z : any
55+
56+
constructor(z: string) {
57+
>z : string
58+
}
59+
}
60+
+35Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// @target: esnext
2+
// @useDefineForClassFields: true
3+
4+
5+
// With useDefineForClassFields: true and ESNext target, initializer
6+
// expressions for property declarations are evaluated in the scope of
7+
// the class body and are permitted to reference parameters or local
8+
// variables of the constructor. This is different from classic
9+
// Typescript behaviour, with useDefineForClassFields: false. There,
10+
// initialisers of property declarations are evaluated in the scope of
11+
// the constructor body.
12+
13+
// Note that when class fields are accepted in the ECMAScript
14+
// standard, the target will become that year's ES20xx
15+
16+
var x = 1;
17+
class C {
18+
b = x; // ok
19+
constructor(x: string) {
20+
}
21+
}
22+
23+
var y = 1;
24+
class D {
25+
b = y; // ok
26+
constructor(x: string) {
27+
var y = "";
28+
}
29+
}
30+
31+
class E {
32+
b = z; // not ok
33+
constructor(z: string) {
34+
}
35+
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.