mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-06-10 18:04:18 -05:00
Class fields w/esnext+[[Define]]:no shadow error (#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
This commit is contained in:
committed by
GitHub
parent
8da3eff7b0
commit
36169b4d13
@@ -1822,9 +1822,10 @@ namespace ts {
|
||||
|
||||
// Perform extra checks only if error reporting was requested
|
||||
if (nameNotFoundMessage) {
|
||||
if (propertyWithInvalidInitializer) {
|
||||
if (propertyWithInvalidInitializer && !(compilerOptions.target === ScriptTarget.ESNext && compilerOptions.useDefineForClassFields)) {
|
||||
// We have a match, but the reference occurred within a property initializer and the identifier also binds
|
||||
// to a local variable in the constructor where the code will be emitted.
|
||||
// to a local variable in the constructor where the code will be emitted. Note that this is actually allowed
|
||||
// with ESNext+useDefineForClassFields because the scope semantics are different.
|
||||
const propertyName = (<PropertyDeclaration>propertyWithInvalidInitializer).name;
|
||||
error(errorLocation, Diagnostics.Initializer_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor,
|
||||
declarationNameToString(propertyName), diagnosticName(nameArg!));
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
tests/cases/conformance/classes/propertyMemberDeclarations/constructorParameterShadowsOuterScopes2.ts(28,9): error TS2304: Cannot find name 'z'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/classes/propertyMemberDeclarations/constructorParameterShadowsOuterScopes2.ts (1 errors) ====
|
||||
// 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
|
||||
|
||||
var x = 1;
|
||||
class C {
|
||||
b = x; // ok
|
||||
constructor(x: string) {
|
||||
}
|
||||
}
|
||||
|
||||
var y = 1;
|
||||
class D {
|
||||
b = y; // ok
|
||||
constructor(x: string) {
|
||||
var y = "";
|
||||
}
|
||||
}
|
||||
|
||||
class E {
|
||||
b = z; // not ok
|
||||
~
|
||||
!!! error TS2304: Cannot find name 'z'.
|
||||
constructor(z: string) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
//// [constructorParameterShadowsOuterScopes2.ts]
|
||||
// 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
|
||||
|
||||
var x = 1;
|
||||
class C {
|
||||
b = x; // ok
|
||||
constructor(x: string) {
|
||||
}
|
||||
}
|
||||
|
||||
var y = 1;
|
||||
class D {
|
||||
b = y; // ok
|
||||
constructor(x: string) {
|
||||
var y = "";
|
||||
}
|
||||
}
|
||||
|
||||
class E {
|
||||
b = z; // not ok
|
||||
constructor(z: string) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//// [constructorParameterShadowsOuterScopes2.js]
|
||||
// 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
|
||||
var x = 1;
|
||||
class C {
|
||||
b = x; // ok
|
||||
constructor(x) {
|
||||
}
|
||||
}
|
||||
var y = 1;
|
||||
class D {
|
||||
b = y; // ok
|
||||
constructor(x) {
|
||||
var y = "";
|
||||
}
|
||||
}
|
||||
class E {
|
||||
b = z; // not ok
|
||||
constructor(z) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
=== tests/cases/conformance/classes/propertyMemberDeclarations/constructorParameterShadowsOuterScopes2.ts ===
|
||||
// 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
|
||||
|
||||
var x = 1;
|
||||
>x : Symbol(x, Decl(constructorParameterShadowsOuterScopes2.ts, 11, 3))
|
||||
|
||||
class C {
|
||||
>C : Symbol(C, Decl(constructorParameterShadowsOuterScopes2.ts, 11, 10))
|
||||
|
||||
b = x; // ok
|
||||
>b : Symbol(C.b, Decl(constructorParameterShadowsOuterScopes2.ts, 12, 9))
|
||||
>x : Symbol(x, Decl(constructorParameterShadowsOuterScopes2.ts, 11, 3))
|
||||
|
||||
constructor(x: string) {
|
||||
>x : Symbol(x, Decl(constructorParameterShadowsOuterScopes2.ts, 14, 16))
|
||||
}
|
||||
}
|
||||
|
||||
var y = 1;
|
||||
>y : Symbol(y, Decl(constructorParameterShadowsOuterScopes2.ts, 18, 3))
|
||||
|
||||
class D {
|
||||
>D : Symbol(D, Decl(constructorParameterShadowsOuterScopes2.ts, 18, 10))
|
||||
|
||||
b = y; // ok
|
||||
>b : Symbol(D.b, Decl(constructorParameterShadowsOuterScopes2.ts, 19, 9))
|
||||
>y : Symbol(y, Decl(constructorParameterShadowsOuterScopes2.ts, 18, 3))
|
||||
|
||||
constructor(x: string) {
|
||||
>x : Symbol(x, Decl(constructorParameterShadowsOuterScopes2.ts, 21, 16))
|
||||
|
||||
var y = "";
|
||||
>y : Symbol(y, Decl(constructorParameterShadowsOuterScopes2.ts, 22, 11))
|
||||
}
|
||||
}
|
||||
|
||||
class E {
|
||||
>E : Symbol(E, Decl(constructorParameterShadowsOuterScopes2.ts, 24, 1))
|
||||
|
||||
b = z; // not ok
|
||||
>b : Symbol(E.b, Decl(constructorParameterShadowsOuterScopes2.ts, 26, 9))
|
||||
|
||||
constructor(z: string) {
|
||||
>z : Symbol(z, Decl(constructorParameterShadowsOuterScopes2.ts, 28, 16))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
=== tests/cases/conformance/classes/propertyMemberDeclarations/constructorParameterShadowsOuterScopes2.ts ===
|
||||
// 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
|
||||
|
||||
var x = 1;
|
||||
>x : number
|
||||
>1 : 1
|
||||
|
||||
class C {
|
||||
>C : C
|
||||
|
||||
b = x; // ok
|
||||
>b : number
|
||||
>x : number
|
||||
|
||||
constructor(x: string) {
|
||||
>x : string
|
||||
}
|
||||
}
|
||||
|
||||
var y = 1;
|
||||
>y : number
|
||||
>1 : 1
|
||||
|
||||
class D {
|
||||
>D : D
|
||||
|
||||
b = y; // ok
|
||||
>b : number
|
||||
>y : number
|
||||
|
||||
constructor(x: string) {
|
||||
>x : string
|
||||
|
||||
var y = "";
|
||||
>y : string
|
||||
>"" : ""
|
||||
}
|
||||
}
|
||||
|
||||
class E {
|
||||
>E : E
|
||||
|
||||
b = z; // not ok
|
||||
>b : any
|
||||
>z : any
|
||||
|
||||
constructor(z: string) {
|
||||
>z : string
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
// @target: esnext
|
||||
// @useDefineForClassFields: true
|
||||
|
||||
|
||||
// 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
|
||||
|
||||
var x = 1;
|
||||
class C {
|
||||
b = x; // ok
|
||||
constructor(x: string) {
|
||||
}
|
||||
}
|
||||
|
||||
var y = 1;
|
||||
class D {
|
||||
b = y; // ok
|
||||
constructor(x: string) {
|
||||
var y = "";
|
||||
}
|
||||
}
|
||||
|
||||
class E {
|
||||
b = z; // not ok
|
||||
constructor(z: string) {
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user