fix use-before-init error when targeting ES2022 (#55028)

This commit is contained in:
Zzzen
2023-07-28 16:02:09 -07:00
committed by GitHub
parent 6037cf5db8
commit 23eabea067
25 changed files with 824 additions and 19 deletions
+13 -11
View File
@@ -274,6 +274,7 @@ import {
getEmitModuleKind,
getEmitModuleResolutionKind,
getEmitScriptTarget,
getEmitStandardClassFields,
getEnclosingBlockScopeContainer,
getEnclosingContainer,
getEntityNameFromTypeNode,
@@ -1437,6 +1438,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
var moduleKind = getEmitModuleKind(compilerOptions);
var legacyDecorators = !!compilerOptions.experimentalDecorators;
var useDefineForClassFields = getUseDefineForClassFields(compilerOptions);
var emitStandardClassFields = getEmitStandardClassFields(compilerOptions);
var allowSyntheticDefaultImports = getAllowSyntheticDefaultImports(compilerOptions);
var strictNullChecks = getStrictOptionValue(compilerOptions, "strictNullChecks");
var strictFunctionTypes = getStrictOptionValue(compilerOptions, "strictFunctionTypes");
@@ -2785,8 +2787,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
return !isPropertyImmediatelyReferencedWithinDeclaration(declaration, usage, /*stopAtAnyPropertyDeclaration*/ false);
}
else if (isParameterPropertyDeclaration(declaration, declaration.parent)) {
// foo = this.bar is illegal in esnext+useDefineForClassFields when bar is a parameter property
return !(getEmitScriptTarget(compilerOptions) === ScriptTarget.ESNext && useDefineForClassFields
// foo = this.bar is illegal in emitStandardClassFields when bar is a parameter property
return !(emitStandardClassFields
&& getContainingClass(declaration) === getContainingClass(usage)
&& isUsedInFunctionOrInstanceProperty(usage, declaration));
}
@@ -2798,7 +2800,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
// 1. inside an export specifier
// 2. inside a function
// 3. inside an instance property initializer, a reference to a non-instance property
// (except when target: "esnext" and useDefineForClassFields: true and the reference is to a parameter property)
// (except when emitStandardClassFields: true and the reference is to a parameter property)
// 4. inside a static property initializer, a reference to a static method in the same class
// 5. inside a TS export= declaration (since we will move the export statement during emit to avoid TDZ)
// or if usage is in a type context:
@@ -2817,7 +2819,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
return true;
}
if (isUsedInFunctionOrInstanceProperty(usage, declaration)) {
if (getEmitScriptTarget(compilerOptions) >= ScriptTarget.ES2022 && useDefineForClassFields
if (emitStandardClassFields
&& getContainingClass(declaration)
&& (isPropertyDeclaration(declaration) || isParameterPropertyDeclaration(declaration, declaration.parent))) {
return !isPropertyImmediatelyReferencedWithinDeclaration(declaration, usage, /*stopAtAnyPropertyDeclaration*/ true);
@@ -2974,7 +2976,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
case SyntaxKind.PropertyDeclaration:
// static properties in classes introduce temporary variables
if (hasStaticModifier(node)) {
return target < ScriptTarget.ESNext || !useDefineForClassFields;
return !emitStandardClassFields;
}
return requiresScopeChangeWorker((node as PropertyDeclaration).name);
default:
@@ -3392,10 +3394,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
// 1. When result is undefined, after checking for a missing "this."
// 2. When result is defined
function checkAndReportErrorForInvalidInitializer() {
if (propertyWithInvalidInitializer && !(useDefineForClassFields && getEmitScriptTarget(compilerOptions) >= ScriptTarget.ES2022)) {
if (propertyWithInvalidInitializer && !emitStandardClassFields) {
// 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. Note that this is actually allowed
// with ESNext+useDefineForClassFields because the scope semantics are different.
// with emitStandardClassFields because the scope semantics are different.
error(errorLocation,
errorLocation && propertyWithInvalidInitializer.type && textRangeContainsPositionInclusive(propertyWithInvalidInitializer.type, errorLocation.pos)
? Diagnostics.Type_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor
@@ -31739,7 +31741,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
&& !(isAccessExpression(node) && isAccessExpression(node.expression))
&& !isBlockScopedNameDeclaredBeforeUse(valueDeclaration, right)
&& !(isMethodDeclaration(valueDeclaration) && getCombinedModifierFlagsCached(valueDeclaration) & ModifierFlags.Static)
&& (compilerOptions.useDefineForClassFields || !isPropertyDeclaredInAncestorClass(prop))) {
&& (useDefineForClassFields || !isPropertyDeclaredInAncestorClass(prop))) {
diagnosticMessage = error(right, Diagnostics.Property_0_is_used_before_its_initialization, declarationName);
}
else if (valueDeclaration.kind === SyntaxKind.ClassDeclaration &&
@@ -38453,7 +38455,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
case "length":
case "caller":
case "arguments":
if (compilerOptions.useDefineForClassFields) {
if (useDefineForClassFields) {
break;
}
// fall through
@@ -38658,7 +38660,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
// or the containing class declares instance member variables with initializers.
const superCallShouldBeRootLevel =
(getEmitScriptTarget(compilerOptions) !== ScriptTarget.ESNext || !useDefineForClassFields) &&
!emitStandardClassFields &&
(some((node.parent as ClassDeclaration).members, isInstancePropertyWithInitializerOrPrivateIdentifierProperty) ||
some(node.parameters, p => hasSyntacticModifier(p, ModifierFlags.ParameterPropertyModifier)));
@@ -42935,7 +42937,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
!legacyDecorators && languageVersion < ScriptTarget.ESNext &&
classOrConstructorParameterIsDecorated(/*useLegacyDecorators*/ false, node);
const willTransformPrivateElementsOrClassStaticBlocks = languageVersion <= ScriptTarget.ES2022;
const willTransformInitializers = !useDefineForClassFields || languageVersion < ScriptTarget.ES2022;
const willTransformInitializers = !emitStandardClassFields;
if (willTransformStaticElementsOfDecoratedClass || willTransformPrivateElementsOrClassStaticBlocks) {
for (const member of node.members) {
if (willTransformStaticElementsOfDecoratedClass && classElementOrClassElementParameterIsDecorated(/*useLegacyDecorators*/ false, member, node)) {
+5
View File
@@ -8666,6 +8666,11 @@ export function getUseDefineForClassFields(compilerOptions: CompilerOptions): bo
return compilerOptions.useDefineForClassFields === undefined ? getEmitScriptTarget(compilerOptions) >= ScriptTarget.ES2022 : compilerOptions.useDefineForClassFields;
}
/** @internal */
export function getEmitStandardClassFields(compilerOptions: CompilerOptions) {
return compilerOptions.useDefineForClassFields !== false && getEmitScriptTarget(compilerOptions) >= ScriptTarget.ES2022;
}
/** @internal */
export function compilerOptionsAffectSemanticDiagnostics(newOptions: CompilerOptions, oldOptions: CompilerOptions): boolean {
return optionsHaveChanges(oldOptions, newOptions, semanticDiagnosticsOptionDeclarations);
@@ -2,9 +2,10 @@ assignParameterPropertyToPropertyDeclarationES2022.ts(2,16): error TS2729: Prope
assignParameterPropertyToPropertyDeclarationES2022.ts(3,16): error TS2729: Property 'foo' is used before its initialization.
assignParameterPropertyToPropertyDeclarationES2022.ts(6,19): error TS2729: Property 'm3' is used before its initialization.
assignParameterPropertyToPropertyDeclarationES2022.ts(12,17): error TS2729: Property 'baz' is used before its initialization.
assignParameterPropertyToPropertyDeclarationES2022.ts(13,16): error TS2729: Property 'foo' is used before its initialization.
==== assignParameterPropertyToPropertyDeclarationES2022.ts (4 errors) ====
==== assignParameterPropertyToPropertyDeclarationES2022.ts (5 errors) ====
class C {
qux = this.bar // should error
~~~
@@ -30,6 +31,9 @@ assignParameterPropertyToPropertyDeclarationES2022.ts(12,17): error TS2729: Prop
!!! error TS2729: Property 'baz' is used before its initialization.
!!! related TS2728 assignParameterPropertyToPropertyDeclarationES2022.ts:13:5: 'baz' is declared here.
baz = this.foo; // should error
~~~
!!! error TS2729: Property 'foo' is used before its initialization.
!!! related TS2728 assignParameterPropertyToPropertyDeclarationES2022.ts:11:17: 'foo' is declared here.
quid = this.baz // ok
m2() {
this.foo // ok
@@ -0,0 +1,33 @@
//// [tests/cases/conformance/classes/propertyMemberDeclarations/initializationOrdering1.ts] ////
//// [initializationOrdering1.ts]
class Helper {
create(): boolean {
return true
}
}
export class Broken {
constructor(readonly facade: Helper) {
console.log(this.bug)
}
bug = this.facade.create()
}
new Broken(new Helper)
//// [initializationOrdering1.js]
class Helper {
create() {
return true;
}
}
export class Broken {
constructor(facade) {
this.facade = facade;
this.bug = this.facade.create();
console.log(this.bug);
}
}
new Broken(new Helper);
@@ -0,0 +1,42 @@
//// [tests/cases/conformance/classes/propertyMemberDeclarations/initializationOrdering1.ts] ////
=== initializationOrdering1.ts ===
class Helper {
>Helper : Symbol(Helper, Decl(initializationOrdering1.ts, 0, 0))
create(): boolean {
>create : Symbol(Helper.create, Decl(initializationOrdering1.ts, 0, 14))
return true
}
}
export class Broken {
>Broken : Symbol(Broken, Decl(initializationOrdering1.ts, 4, 1))
constructor(readonly facade: Helper) {
>facade : Symbol(Broken.facade, Decl(initializationOrdering1.ts, 7, 16))
>Helper : Symbol(Helper, Decl(initializationOrdering1.ts, 0, 0))
console.log(this.bug)
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>this.bug : Symbol(Broken.bug, Decl(initializationOrdering1.ts, 9, 5))
>this : Symbol(Broken, Decl(initializationOrdering1.ts, 4, 1))
>bug : Symbol(Broken.bug, Decl(initializationOrdering1.ts, 9, 5))
}
bug = this.facade.create()
>bug : Symbol(Broken.bug, Decl(initializationOrdering1.ts, 9, 5))
>this.facade.create : Symbol(Helper.create, Decl(initializationOrdering1.ts, 0, 14))
>this.facade : Symbol(Broken.facade, Decl(initializationOrdering1.ts, 7, 16))
>this : Symbol(Broken, Decl(initializationOrdering1.ts, 4, 1))
>facade : Symbol(Broken.facade, Decl(initializationOrdering1.ts, 7, 16))
>create : Symbol(Helper.create, Decl(initializationOrdering1.ts, 0, 14))
}
new Broken(new Helper)
>Broken : Symbol(Broken, Decl(initializationOrdering1.ts, 4, 1))
>Helper : Symbol(Helper, Decl(initializationOrdering1.ts, 0, 0))
@@ -0,0 +1,46 @@
//// [tests/cases/conformance/classes/propertyMemberDeclarations/initializationOrdering1.ts] ////
=== initializationOrdering1.ts ===
class Helper {
>Helper : Helper
create(): boolean {
>create : () => boolean
return true
>true : true
}
}
export class Broken {
>Broken : Broken
constructor(readonly facade: Helper) {
>facade : Helper
console.log(this.bug)
>console.log(this.bug) : void
>console.log : (...data: any[]) => void
>console : Console
>log : (...data: any[]) => void
>this.bug : boolean
>this : this
>bug : boolean
}
bug = this.facade.create()
>bug : boolean
>this.facade.create() : boolean
>this.facade.create : () => boolean
>this.facade : Helper
>this : this
>facade : Helper
>create : () => boolean
}
new Broken(new Helper)
>new Broken(new Helper) : Broken
>Broken : typeof Broken
>new Helper : Helper
>Helper : typeof Helper
@@ -0,0 +1,43 @@
//// [tests/cases/conformance/classes/propertyMemberDeclarations/initializationOrdering1.ts] ////
//// [initializationOrdering1.ts]
class Helper {
create(): boolean {
return true
}
}
export class Broken {
constructor(readonly facade: Helper) {
console.log(this.bug)
}
bug = this.facade.create()
}
new Broken(new Helper)
//// [initializationOrdering1.js]
class Helper {
create() {
return true;
}
}
export class Broken {
constructor(facade) {
Object.defineProperty(this, "facade", {
enumerable: true,
configurable: true,
writable: true,
value: facade
});
Object.defineProperty(this, "bug", {
enumerable: true,
configurable: true,
writable: true,
value: this.facade.create()
});
console.log(this.bug);
}
}
new Broken(new Helper);
@@ -0,0 +1,42 @@
//// [tests/cases/conformance/classes/propertyMemberDeclarations/initializationOrdering1.ts] ////
=== initializationOrdering1.ts ===
class Helper {
>Helper : Symbol(Helper, Decl(initializationOrdering1.ts, 0, 0))
create(): boolean {
>create : Symbol(Helper.create, Decl(initializationOrdering1.ts, 0, 14))
return true
}
}
export class Broken {
>Broken : Symbol(Broken, Decl(initializationOrdering1.ts, 4, 1))
constructor(readonly facade: Helper) {
>facade : Symbol(Broken.facade, Decl(initializationOrdering1.ts, 7, 16))
>Helper : Symbol(Helper, Decl(initializationOrdering1.ts, 0, 0))
console.log(this.bug)
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>this.bug : Symbol(Broken.bug, Decl(initializationOrdering1.ts, 9, 5))
>this : Symbol(Broken, Decl(initializationOrdering1.ts, 4, 1))
>bug : Symbol(Broken.bug, Decl(initializationOrdering1.ts, 9, 5))
}
bug = this.facade.create()
>bug : Symbol(Broken.bug, Decl(initializationOrdering1.ts, 9, 5))
>this.facade.create : Symbol(Helper.create, Decl(initializationOrdering1.ts, 0, 14))
>this.facade : Symbol(Broken.facade, Decl(initializationOrdering1.ts, 7, 16))
>this : Symbol(Broken, Decl(initializationOrdering1.ts, 4, 1))
>facade : Symbol(Broken.facade, Decl(initializationOrdering1.ts, 7, 16))
>create : Symbol(Helper.create, Decl(initializationOrdering1.ts, 0, 14))
}
new Broken(new Helper)
>Broken : Symbol(Broken, Decl(initializationOrdering1.ts, 4, 1))
>Helper : Symbol(Helper, Decl(initializationOrdering1.ts, 0, 0))
@@ -0,0 +1,46 @@
//// [tests/cases/conformance/classes/propertyMemberDeclarations/initializationOrdering1.ts] ////
=== initializationOrdering1.ts ===
class Helper {
>Helper : Helper
create(): boolean {
>create : () => boolean
return true
>true : true
}
}
export class Broken {
>Broken : Broken
constructor(readonly facade: Helper) {
>facade : Helper
console.log(this.bug)
>console.log(this.bug) : void
>console.log : (...data: any[]) => void
>console : Console
>log : (...data: any[]) => void
>this.bug : boolean
>this : this
>bug : boolean
}
bug = this.facade.create()
>bug : boolean
>this.facade.create() : boolean
>this.facade.create : () => boolean
>this.facade : Helper
>this : this
>facade : Helper
>create : () => boolean
}
new Broken(new Helper)
>new Broken(new Helper) : Broken
>Broken : typeof Broken
>new Helper : Helper
>Helper : typeof Helper
@@ -0,0 +1,33 @@
//// [tests/cases/conformance/classes/propertyMemberDeclarations/initializationOrdering1.ts] ////
//// [initializationOrdering1.ts]
class Helper {
create(): boolean {
return true
}
}
export class Broken {
constructor(readonly facade: Helper) {
console.log(this.bug)
}
bug = this.facade.create()
}
new Broken(new Helper)
//// [initializationOrdering1.js]
class Helper {
create() {
return true;
}
}
export class Broken {
constructor(facade) {
this.facade = facade;
this.bug = this.facade.create();
console.log(this.bug);
}
}
new Broken(new Helper);
@@ -0,0 +1,42 @@
//// [tests/cases/conformance/classes/propertyMemberDeclarations/initializationOrdering1.ts] ////
=== initializationOrdering1.ts ===
class Helper {
>Helper : Symbol(Helper, Decl(initializationOrdering1.ts, 0, 0))
create(): boolean {
>create : Symbol(Helper.create, Decl(initializationOrdering1.ts, 0, 14))
return true
}
}
export class Broken {
>Broken : Symbol(Broken, Decl(initializationOrdering1.ts, 4, 1))
constructor(readonly facade: Helper) {
>facade : Symbol(Broken.facade, Decl(initializationOrdering1.ts, 7, 16))
>Helper : Symbol(Helper, Decl(initializationOrdering1.ts, 0, 0))
console.log(this.bug)
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>this.bug : Symbol(Broken.bug, Decl(initializationOrdering1.ts, 9, 5))
>this : Symbol(Broken, Decl(initializationOrdering1.ts, 4, 1))
>bug : Symbol(Broken.bug, Decl(initializationOrdering1.ts, 9, 5))
}
bug = this.facade.create()
>bug : Symbol(Broken.bug, Decl(initializationOrdering1.ts, 9, 5))
>this.facade.create : Symbol(Helper.create, Decl(initializationOrdering1.ts, 0, 14))
>this.facade : Symbol(Broken.facade, Decl(initializationOrdering1.ts, 7, 16))
>this : Symbol(Broken, Decl(initializationOrdering1.ts, 4, 1))
>facade : Symbol(Broken.facade, Decl(initializationOrdering1.ts, 7, 16))
>create : Symbol(Helper.create, Decl(initializationOrdering1.ts, 0, 14))
}
new Broken(new Helper)
>Broken : Symbol(Broken, Decl(initializationOrdering1.ts, 4, 1))
>Helper : Symbol(Helper, Decl(initializationOrdering1.ts, 0, 0))
@@ -0,0 +1,46 @@
//// [tests/cases/conformance/classes/propertyMemberDeclarations/initializationOrdering1.ts] ////
=== initializationOrdering1.ts ===
class Helper {
>Helper : Helper
create(): boolean {
>create : () => boolean
return true
>true : true
}
}
export class Broken {
>Broken : Broken
constructor(readonly facade: Helper) {
>facade : Helper
console.log(this.bug)
>console.log(this.bug) : void
>console.log : (...data: any[]) => void
>console : Console
>log : (...data: any[]) => void
>this.bug : boolean
>this : this
>bug : boolean
}
bug = this.facade.create()
>bug : boolean
>this.facade.create() : boolean
>this.facade.create : () => boolean
>this.facade : Helper
>this : this
>facade : Helper
>create : () => boolean
}
new Broken(new Helper)
>new Broken(new Helper) : Broken
>Broken : typeof Broken
>new Helper : Helper
>Helper : typeof Helper
@@ -0,0 +1,22 @@
initializationOrdering1.ts(11,16): error TS2729: Property 'facade' is used before its initialization.
==== initializationOrdering1.ts (1 errors) ====
class Helper {
create(): boolean {
return true
}
}
export class Broken {
constructor(readonly facade: Helper) {
console.log(this.bug)
}
bug = this.facade.create()
~~~~~~
!!! error TS2729: Property 'facade' is used before its initialization.
!!! related TS2728 initializationOrdering1.ts:8:17: 'facade' is declared here.
}
new Broken(new Helper)
@@ -0,0 +1,34 @@
//// [tests/cases/conformance/classes/propertyMemberDeclarations/initializationOrdering1.ts] ////
//// [initializationOrdering1.ts]
class Helper {
create(): boolean {
return true
}
}
export class Broken {
constructor(readonly facade: Helper) {
console.log(this.bug)
}
bug = this.facade.create()
}
new Broken(new Helper)
//// [initializationOrdering1.js]
class Helper {
create() {
return true;
}
}
export class Broken {
facade;
constructor(facade) {
this.facade = facade;
console.log(this.bug);
}
bug = this.facade.create();
}
new Broken(new Helper);
@@ -0,0 +1,42 @@
//// [tests/cases/conformance/classes/propertyMemberDeclarations/initializationOrdering1.ts] ////
=== initializationOrdering1.ts ===
class Helper {
>Helper : Symbol(Helper, Decl(initializationOrdering1.ts, 0, 0))
create(): boolean {
>create : Symbol(Helper.create, Decl(initializationOrdering1.ts, 0, 14))
return true
}
}
export class Broken {
>Broken : Symbol(Broken, Decl(initializationOrdering1.ts, 4, 1))
constructor(readonly facade: Helper) {
>facade : Symbol(Broken.facade, Decl(initializationOrdering1.ts, 7, 16))
>Helper : Symbol(Helper, Decl(initializationOrdering1.ts, 0, 0))
console.log(this.bug)
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>this.bug : Symbol(Broken.bug, Decl(initializationOrdering1.ts, 9, 5))
>this : Symbol(Broken, Decl(initializationOrdering1.ts, 4, 1))
>bug : Symbol(Broken.bug, Decl(initializationOrdering1.ts, 9, 5))
}
bug = this.facade.create()
>bug : Symbol(Broken.bug, Decl(initializationOrdering1.ts, 9, 5))
>this.facade.create : Symbol(Helper.create, Decl(initializationOrdering1.ts, 0, 14))
>this.facade : Symbol(Broken.facade, Decl(initializationOrdering1.ts, 7, 16))
>this : Symbol(Broken, Decl(initializationOrdering1.ts, 4, 1))
>facade : Symbol(Broken.facade, Decl(initializationOrdering1.ts, 7, 16))
>create : Symbol(Helper.create, Decl(initializationOrdering1.ts, 0, 14))
}
new Broken(new Helper)
>Broken : Symbol(Broken, Decl(initializationOrdering1.ts, 4, 1))
>Helper : Symbol(Helper, Decl(initializationOrdering1.ts, 0, 0))
@@ -0,0 +1,46 @@
//// [tests/cases/conformance/classes/propertyMemberDeclarations/initializationOrdering1.ts] ////
=== initializationOrdering1.ts ===
class Helper {
>Helper : Helper
create(): boolean {
>create : () => boolean
return true
>true : true
}
}
export class Broken {
>Broken : Broken
constructor(readonly facade: Helper) {
>facade : Helper
console.log(this.bug)
>console.log(this.bug) : void
>console.log : (...data: any[]) => void
>console : Console
>log : (...data: any[]) => void
>this.bug : boolean
>this : this
>bug : boolean
}
bug = this.facade.create()
>bug : boolean
>this.facade.create() : boolean
>this.facade.create : () => boolean
>this.facade : Helper
>this : this
>facade : Helper
>create : () => boolean
}
new Broken(new Helper)
>new Broken(new Helper) : Broken
>Broken : typeof Broken
>new Helper : Helper
>Helper : typeof Helper
@@ -0,0 +1,33 @@
//// [tests/cases/conformance/classes/propertyMemberDeclarations/initializationOrdering1.ts] ////
//// [initializationOrdering1.ts]
class Helper {
create(): boolean {
return true
}
}
export class Broken {
constructor(readonly facade: Helper) {
console.log(this.bug)
}
bug = this.facade.create()
}
new Broken(new Helper)
//// [initializationOrdering1.js]
class Helper {
create() {
return true;
}
}
export class Broken {
constructor(facade) {
this.facade = facade;
this.bug = this.facade.create();
console.log(this.bug);
}
}
new Broken(new Helper);
@@ -0,0 +1,42 @@
//// [tests/cases/conformance/classes/propertyMemberDeclarations/initializationOrdering1.ts] ////
=== initializationOrdering1.ts ===
class Helper {
>Helper : Symbol(Helper, Decl(initializationOrdering1.ts, 0, 0))
create(): boolean {
>create : Symbol(Helper.create, Decl(initializationOrdering1.ts, 0, 14))
return true
}
}
export class Broken {
>Broken : Symbol(Broken, Decl(initializationOrdering1.ts, 4, 1))
constructor(readonly facade: Helper) {
>facade : Symbol(Broken.facade, Decl(initializationOrdering1.ts, 7, 16))
>Helper : Symbol(Helper, Decl(initializationOrdering1.ts, 0, 0))
console.log(this.bug)
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>this.bug : Symbol(Broken.bug, Decl(initializationOrdering1.ts, 9, 5))
>this : Symbol(Broken, Decl(initializationOrdering1.ts, 4, 1))
>bug : Symbol(Broken.bug, Decl(initializationOrdering1.ts, 9, 5))
}
bug = this.facade.create()
>bug : Symbol(Broken.bug, Decl(initializationOrdering1.ts, 9, 5))
>this.facade.create : Symbol(Helper.create, Decl(initializationOrdering1.ts, 0, 14))
>this.facade : Symbol(Broken.facade, Decl(initializationOrdering1.ts, 7, 16))
>this : Symbol(Broken, Decl(initializationOrdering1.ts, 4, 1))
>facade : Symbol(Broken.facade, Decl(initializationOrdering1.ts, 7, 16))
>create : Symbol(Helper.create, Decl(initializationOrdering1.ts, 0, 14))
}
new Broken(new Helper)
>Broken : Symbol(Broken, Decl(initializationOrdering1.ts, 4, 1))
>Helper : Symbol(Helper, Decl(initializationOrdering1.ts, 0, 0))
@@ -0,0 +1,46 @@
//// [tests/cases/conformance/classes/propertyMemberDeclarations/initializationOrdering1.ts] ////
=== initializationOrdering1.ts ===
class Helper {
>Helper : Helper
create(): boolean {
>create : () => boolean
return true
>true : true
}
}
export class Broken {
>Broken : Broken
constructor(readonly facade: Helper) {
>facade : Helper
console.log(this.bug)
>console.log(this.bug) : void
>console.log : (...data: any[]) => void
>console : Console
>log : (...data: any[]) => void
>this.bug : boolean
>this : this
>bug : boolean
}
bug = this.facade.create()
>bug : boolean
>this.facade.create() : boolean
>this.facade.create : () => boolean
>this.facade : Helper
>this : this
>facade : Helper
>create : () => boolean
}
new Broken(new Helper)
>new Broken(new Helper) : Broken
>Broken : typeof Broken
>new Helper : Helper
>Helper : typeof Helper
@@ -0,0 +1,22 @@
initializationOrdering1.ts(11,16): error TS2729: Property 'facade' is used before its initialization.
==== initializationOrdering1.ts (1 errors) ====
class Helper {
create(): boolean {
return true
}
}
export class Broken {
constructor(readonly facade: Helper) {
console.log(this.bug)
}
bug = this.facade.create()
~~~~~~
!!! error TS2729: Property 'facade' is used before its initialization.
!!! related TS2728 initializationOrdering1.ts:8:17: 'facade' is declared here.
}
new Broken(new Helper)
@@ -0,0 +1,34 @@
//// [tests/cases/conformance/classes/propertyMemberDeclarations/initializationOrdering1.ts] ////
//// [initializationOrdering1.ts]
class Helper {
create(): boolean {
return true
}
}
export class Broken {
constructor(readonly facade: Helper) {
console.log(this.bug)
}
bug = this.facade.create()
}
new Broken(new Helper)
//// [initializationOrdering1.js]
class Helper {
create() {
return true;
}
}
export class Broken {
facade;
constructor(facade) {
this.facade = facade;
console.log(this.bug);
}
bug = this.facade.create();
}
new Broken(new Helper);
@@ -0,0 +1,42 @@
//// [tests/cases/conformance/classes/propertyMemberDeclarations/initializationOrdering1.ts] ////
=== initializationOrdering1.ts ===
class Helper {
>Helper : Symbol(Helper, Decl(initializationOrdering1.ts, 0, 0))
create(): boolean {
>create : Symbol(Helper.create, Decl(initializationOrdering1.ts, 0, 14))
return true
}
}
export class Broken {
>Broken : Symbol(Broken, Decl(initializationOrdering1.ts, 4, 1))
constructor(readonly facade: Helper) {
>facade : Symbol(Broken.facade, Decl(initializationOrdering1.ts, 7, 16))
>Helper : Symbol(Helper, Decl(initializationOrdering1.ts, 0, 0))
console.log(this.bug)
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>this.bug : Symbol(Broken.bug, Decl(initializationOrdering1.ts, 9, 5))
>this : Symbol(Broken, Decl(initializationOrdering1.ts, 4, 1))
>bug : Symbol(Broken.bug, Decl(initializationOrdering1.ts, 9, 5))
}
bug = this.facade.create()
>bug : Symbol(Broken.bug, Decl(initializationOrdering1.ts, 9, 5))
>this.facade.create : Symbol(Helper.create, Decl(initializationOrdering1.ts, 0, 14))
>this.facade : Symbol(Broken.facade, Decl(initializationOrdering1.ts, 7, 16))
>this : Symbol(Broken, Decl(initializationOrdering1.ts, 4, 1))
>facade : Symbol(Broken.facade, Decl(initializationOrdering1.ts, 7, 16))
>create : Symbol(Helper.create, Decl(initializationOrdering1.ts, 0, 14))
}
new Broken(new Helper)
>Broken : Symbol(Broken, Decl(initializationOrdering1.ts, 4, 1))
>Helper : Symbol(Helper, Decl(initializationOrdering1.ts, 0, 0))
@@ -0,0 +1,46 @@
//// [tests/cases/conformance/classes/propertyMemberDeclarations/initializationOrdering1.ts] ////
=== initializationOrdering1.ts ===
class Helper {
>Helper : Helper
create(): boolean {
>create : () => boolean
return true
>true : true
}
}
export class Broken {
>Broken : Broken
constructor(readonly facade: Helper) {
>facade : Helper
console.log(this.bug)
>console.log(this.bug) : void
>console.log : (...data: any[]) => void
>console : Console
>log : (...data: any[]) => void
>this.bug : boolean
>this : this
>bug : boolean
}
bug = this.facade.create()
>bug : boolean
>this.facade.create() : boolean
>this.facade.create : () => boolean
>this.facade : Helper
>this : this
>facade : Helper
>create : () => boolean
}
new Broken(new Helper)
>new Broken(new Helper) : Broken
>Broken : typeof Broken
>new Helper : Helper
>Helper : typeof Helper
@@ -1,21 +1,15 @@
privateNameBadSuperUseDefineForClassFields.ts(4,3): error TS2376: A 'super' call must be the first statement in the constructor to refer to 'super' or 'this' when a derived class contains initialized properties, parameter properties, or private identifiers.
privateNameBadSuperUseDefineForClassFields.ts(5,5): error TS17009: 'super' must be called before accessing 'this' in the constructor of a derived class.
==== privateNameBadSuperUseDefineForClassFields.ts (2 errors) ====
==== privateNameBadSuperUseDefineForClassFields.ts (1 errors) ====
class B {};
class A extends B {
#x;
constructor() {
~~~~~~~~~~~~~~~
this;
~~~~~~~~~
~~~~
!!! error TS17009: 'super' must be called before accessing 'this' in the constructor of a derived class.
super();
~~~~~~~~~~~~
}
~~~
!!! error TS2376: A 'super' call must be the first statement in the constructor to refer to 'super' or 'this' when a derived class contains initialized properties, parameter properties, or private identifiers.
}
@@ -0,0 +1,18 @@
// @target: esnext, es2021, es2022
// @useDefineForClassFields: true, false
class Helper {
create(): boolean {
return true
}
}
export class Broken {
constructor(readonly facade: Helper) {
console.log(this.bug)
}
bug = this.facade.create()
}
new Broken(new Helper)