Disabled 'used before initialization' error for optional properties (#43100)

* Disabled 'used before initialization' error for optional properties

* Expanded tests to include code snippet from issue
This commit is contained in:
Josh Goldberg 2021-04-02 13:08:10 -04:00 committed by GitHub
parent f9b35cd302
commit 38da7c600c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 121 additions and 38 deletions

View file

@ -11936,6 +11936,10 @@ namespace ts {
return false;
}
function isOptionalPropertyDeclaration(node: Declaration) {
return isPropertyDeclaration(node) && node.questionToken;
}
function isOptionalJSDocPropertyLikeTag(node: Node): node is JSDocPropertyLikeTag {
if (!isJSDocPropertyLikeTag(node)) {
return false;
@ -27115,6 +27119,7 @@ namespace ts {
let diagnosticMessage;
const declarationName = idText(right);
if (isInPropertyInitializer(node)
&& !isOptionalPropertyDeclaration(valueDeclaration)
&& !(isAccessExpression(node) && isAccessExpression(node.expression))
&& !isBlockScopedNameDeclaredBeforeUse(valueDeclaration, right)
&& (compilerOptions.useDefineForClassFields || !isPropertyDeclaredInAncestorClass(prop))) {

View file

@ -1,9 +1,9 @@
tests/cases/compiler/classUsedBeforeInitializedVariables.ts(4,15): error TS2729: Property 'p4' is used before its initialization.
tests/cases/compiler/classUsedBeforeInitializedVariables.ts(7,34): error TS2729: Property 'directlyAssigned' is used before its initialization.
tests/cases/compiler/classUsedBeforeInitializedVariables.ts(16,15): error TS2729: Property 'withinObjectLiteral' is used before its initialization.
tests/cases/compiler/classUsedBeforeInitializedVariables.ts(20,19): error TS2729: Property 'withinObjectLiteralGetterName' is used before its initialization.
tests/cases/compiler/classUsedBeforeInitializedVariables.ts(26,19): error TS2729: Property 'withinObjectLiteralSetterName' is used before its initialization.
tests/cases/compiler/classUsedBeforeInitializedVariables.ts(29,64): error TS2729: Property 'withinClassDeclarationExtension' is used before its initialization.
tests/cases/compiler/classUsedBeforeInitializedVariables.ts(13,34): error TS2729: Property 'directlyAssigned' is used before its initialization.
tests/cases/compiler/classUsedBeforeInitializedVariables.ts(22,15): error TS2729: Property 'withinObjectLiteral' is used before its initialization.
tests/cases/compiler/classUsedBeforeInitializedVariables.ts(26,19): error TS2729: Property 'withinObjectLiteralGetterName' is used before its initialization.
tests/cases/compiler/classUsedBeforeInitializedVariables.ts(32,19): error TS2729: Property 'withinObjectLiteralSetterName' is used before its initialization.
tests/cases/compiler/classUsedBeforeInitializedVariables.ts(35,64): error TS2729: Property 'withinClassDeclarationExtension' is used before its initialization.
==== tests/cases/compiler/classUsedBeforeInitializedVariables.ts (6 errors) ====
@ -15,11 +15,17 @@ tests/cases/compiler/classUsedBeforeInitializedVariables.ts(29,64): error TS2729
!!! error TS2729: Property 'p4' is used before its initialization.
!!! related TS2728 tests/cases/compiler/classUsedBeforeInitializedVariables.ts:5:5: 'p4' is declared here.
p4 = 0;
p5?: number;
p6?: string;
p7 = {
hello: (this.p6 = "string"),
};
directlyAssigned: any = this.directlyAssigned;
~~~~~~~~~~~~~~~~
!!! error TS2729: Property 'directlyAssigned' is used before its initialization.
!!! related TS2728 tests/cases/compiler/classUsedBeforeInitializedVariables.ts:7:5: 'directlyAssigned' is declared here.
!!! related TS2728 tests/cases/compiler/classUsedBeforeInitializedVariables.ts:13:5: 'directlyAssigned' is declared here.
withinArrowFunction: any = () => this.withinArrowFunction;
@ -31,14 +37,14 @@ tests/cases/compiler/classUsedBeforeInitializedVariables.ts(29,64): error TS2729
[this.withinObjectLiteral]: true,
~~~~~~~~~~~~~~~~~~~
!!! error TS2729: Property 'withinObjectLiteral' is used before its initialization.
!!! related TS2728 tests/cases/compiler/classUsedBeforeInitializedVariables.ts:15:5: 'withinObjectLiteral' is declared here.
!!! related TS2728 tests/cases/compiler/classUsedBeforeInitializedVariables.ts:21:5: 'withinObjectLiteral' is declared here.
};
withinObjectLiteralGetterName: any = {
get [this.withinObjectLiteralGetterName]() {
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2729: Property 'withinObjectLiteralGetterName' is used before its initialization.
!!! related TS2728 tests/cases/compiler/classUsedBeforeInitializedVariables.ts:19:5: 'withinObjectLiteralGetterName' is declared here.
!!! related TS2728 tests/cases/compiler/classUsedBeforeInitializedVariables.ts:25:5: 'withinObjectLiteralGetterName' is declared here.
return true;
}
};
@ -47,13 +53,15 @@ tests/cases/compiler/classUsedBeforeInitializedVariables.ts(29,64): error TS2729
set [this.withinObjectLiteralSetterName](_: any) {}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2729: Property 'withinObjectLiteralSetterName' is used before its initialization.
!!! related TS2728 tests/cases/compiler/classUsedBeforeInitializedVariables.ts:25:5: 'withinObjectLiteralSetterName' is declared here.
!!! related TS2728 tests/cases/compiler/classUsedBeforeInitializedVariables.ts:31:5: 'withinObjectLiteralSetterName' is declared here.
};
withinClassDeclarationExtension: any = (class extends this.withinClassDeclarationExtension { });
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2729: Property 'withinClassDeclarationExtension' is used before its initialization.
!!! related TS2728 tests/cases/compiler/classUsedBeforeInitializedVariables.ts:29:5: 'withinClassDeclarationExtension' is declared here.
!!! related TS2728 tests/cases/compiler/classUsedBeforeInitializedVariables.ts:35:5: 'withinClassDeclarationExtension' is declared here.
fromOptional = this.p5;
// These error cases are ignored (not checked by control flow analysis)

View file

@ -4,6 +4,12 @@ class Test {
p2 = this.p1;
p3 = this.p4;
p4 = 0;
p5?: number;
p6?: string;
p7 = {
hello: (this.p6 = "string"),
};
directlyAssigned: any = this.directlyAssigned;
@ -29,6 +35,8 @@ class Test {
withinClassDeclarationExtension: any = (class extends this.withinClassDeclarationExtension { });
fromOptional = this.p5;
// These error cases are ignored (not checked by control flow analysis)
assignedByArrowFunction: any = (() => this.assignedByFunction)();
@ -63,6 +71,9 @@ var Test = /** @class */ (function () {
this.p2 = this.p1;
this.p3 = this.p4;
this.p4 = 0;
this.p7 = {
hello: (this.p6 = "string"),
};
this.directlyAssigned = this.directlyAssigned;
this.withinArrowFunction = function () { return _this.withinArrowFunction; };
this.withinFunction = function () {
@ -94,6 +105,7 @@ var Test = /** @class */ (function () {
}
return class_1;
}(this.withinClassDeclarationExtension)));
this.fromOptional = this.p5;
// These error cases are ignored (not checked by control flow analysis)
this.assignedByArrowFunction = (function () { return _this.assignedByFunction; })();
this.assignedByFunction = (function () {

View file

@ -20,76 +20,99 @@ class Test {
p4 = 0;
>p4 : Symbol(Test.p4, Decl(classUsedBeforeInitializedVariables.ts, 3, 17))
directlyAssigned: any = this.directlyAssigned;
>directlyAssigned : Symbol(Test.directlyAssigned, Decl(classUsedBeforeInitializedVariables.ts, 4, 11))
>this.directlyAssigned : Symbol(Test.directlyAssigned, Decl(classUsedBeforeInitializedVariables.ts, 4, 11))
p5?: number;
>p5 : Symbol(Test.p5, Decl(classUsedBeforeInitializedVariables.ts, 4, 11))
p6?: string;
>p6 : Symbol(Test.p6, Decl(classUsedBeforeInitializedVariables.ts, 5, 16))
p7 = {
>p7 : Symbol(Test.p7, Decl(classUsedBeforeInitializedVariables.ts, 7, 16))
hello: (this.p6 = "string"),
>hello : Symbol(hello, Decl(classUsedBeforeInitializedVariables.ts, 8, 10))
>this.p6 : Symbol(Test.p6, Decl(classUsedBeforeInitializedVariables.ts, 5, 16))
>this : Symbol(Test, Decl(classUsedBeforeInitializedVariables.ts, 0, 0))
>directlyAssigned : Symbol(Test.directlyAssigned, Decl(classUsedBeforeInitializedVariables.ts, 4, 11))
>p6 : Symbol(Test.p6, Decl(classUsedBeforeInitializedVariables.ts, 5, 16))
};
directlyAssigned: any = this.directlyAssigned;
>directlyAssigned : Symbol(Test.directlyAssigned, Decl(classUsedBeforeInitializedVariables.ts, 10, 6))
>this.directlyAssigned : Symbol(Test.directlyAssigned, Decl(classUsedBeforeInitializedVariables.ts, 10, 6))
>this : Symbol(Test, Decl(classUsedBeforeInitializedVariables.ts, 0, 0))
>directlyAssigned : Symbol(Test.directlyAssigned, Decl(classUsedBeforeInitializedVariables.ts, 10, 6))
withinArrowFunction: any = () => this.withinArrowFunction;
>withinArrowFunction : Symbol(Test.withinArrowFunction, Decl(classUsedBeforeInitializedVariables.ts, 6, 50))
>this.withinArrowFunction : Symbol(Test.withinArrowFunction, Decl(classUsedBeforeInitializedVariables.ts, 6, 50))
>withinArrowFunction : Symbol(Test.withinArrowFunction, Decl(classUsedBeforeInitializedVariables.ts, 12, 50))
>this.withinArrowFunction : Symbol(Test.withinArrowFunction, Decl(classUsedBeforeInitializedVariables.ts, 12, 50))
>this : Symbol(Test, Decl(classUsedBeforeInitializedVariables.ts, 0, 0))
>withinArrowFunction : Symbol(Test.withinArrowFunction, Decl(classUsedBeforeInitializedVariables.ts, 6, 50))
>withinArrowFunction : Symbol(Test.withinArrowFunction, Decl(classUsedBeforeInitializedVariables.ts, 12, 50))
withinFunction: any = function () {
>withinFunction : Symbol(Test.withinFunction, Decl(classUsedBeforeInitializedVariables.ts, 8, 62))
>withinFunction : Symbol(Test.withinFunction, Decl(classUsedBeforeInitializedVariables.ts, 14, 62))
return this.withinFunction;
};
withinObjectLiteral: any = {
>withinObjectLiteral : Symbol(Test.withinObjectLiteral, Decl(classUsedBeforeInitializedVariables.ts, 12, 6))
>withinObjectLiteral : Symbol(Test.withinObjectLiteral, Decl(classUsedBeforeInitializedVariables.ts, 18, 6))
[this.withinObjectLiteral]: true,
>[this.withinObjectLiteral] : Symbol([this.withinObjectLiteral], Decl(classUsedBeforeInitializedVariables.ts, 14, 32))
>this.withinObjectLiteral : Symbol(Test.withinObjectLiteral, Decl(classUsedBeforeInitializedVariables.ts, 12, 6))
>[this.withinObjectLiteral] : Symbol([this.withinObjectLiteral], Decl(classUsedBeforeInitializedVariables.ts, 20, 32))
>this.withinObjectLiteral : Symbol(Test.withinObjectLiteral, Decl(classUsedBeforeInitializedVariables.ts, 18, 6))
>this : Symbol(Test, Decl(classUsedBeforeInitializedVariables.ts, 0, 0))
>withinObjectLiteral : Symbol(Test.withinObjectLiteral, Decl(classUsedBeforeInitializedVariables.ts, 12, 6))
>withinObjectLiteral : Symbol(Test.withinObjectLiteral, Decl(classUsedBeforeInitializedVariables.ts, 18, 6))
};
withinObjectLiteralGetterName: any = {
>withinObjectLiteralGetterName : Symbol(Test.withinObjectLiteralGetterName, Decl(classUsedBeforeInitializedVariables.ts, 16, 6))
>withinObjectLiteralGetterName : Symbol(Test.withinObjectLiteralGetterName, Decl(classUsedBeforeInitializedVariables.ts, 22, 6))
get [this.withinObjectLiteralGetterName]() {
>[this.withinObjectLiteralGetterName] : Symbol([this.withinObjectLiteralGetterName], Decl(classUsedBeforeInitializedVariables.ts, 18, 42))
>this.withinObjectLiteralGetterName : Symbol(Test.withinObjectLiteralGetterName, Decl(classUsedBeforeInitializedVariables.ts, 16, 6))
>[this.withinObjectLiteralGetterName] : Symbol([this.withinObjectLiteralGetterName], Decl(classUsedBeforeInitializedVariables.ts, 24, 42))
>this.withinObjectLiteralGetterName : Symbol(Test.withinObjectLiteralGetterName, Decl(classUsedBeforeInitializedVariables.ts, 22, 6))
>this : Symbol(Test, Decl(classUsedBeforeInitializedVariables.ts, 0, 0))
>withinObjectLiteralGetterName : Symbol(Test.withinObjectLiteralGetterName, Decl(classUsedBeforeInitializedVariables.ts, 16, 6))
>withinObjectLiteralGetterName : Symbol(Test.withinObjectLiteralGetterName, Decl(classUsedBeforeInitializedVariables.ts, 22, 6))
return true;
}
};
withinObjectLiteralSetterName: any = {
>withinObjectLiteralSetterName : Symbol(Test.withinObjectLiteralSetterName, Decl(classUsedBeforeInitializedVariables.ts, 22, 6))
>withinObjectLiteralSetterName : Symbol(Test.withinObjectLiteralSetterName, Decl(classUsedBeforeInitializedVariables.ts, 28, 6))
set [this.withinObjectLiteralSetterName](_: any) {}
>[this.withinObjectLiteralSetterName] : Symbol([this.withinObjectLiteralSetterName], Decl(classUsedBeforeInitializedVariables.ts, 24, 42))
>this.withinObjectLiteralSetterName : Symbol(Test.withinObjectLiteralSetterName, Decl(classUsedBeforeInitializedVariables.ts, 22, 6))
>[this.withinObjectLiteralSetterName] : Symbol([this.withinObjectLiteralSetterName], Decl(classUsedBeforeInitializedVariables.ts, 30, 42))
>this.withinObjectLiteralSetterName : Symbol(Test.withinObjectLiteralSetterName, Decl(classUsedBeforeInitializedVariables.ts, 28, 6))
>this : Symbol(Test, Decl(classUsedBeforeInitializedVariables.ts, 0, 0))
>withinObjectLiteralSetterName : Symbol(Test.withinObjectLiteralSetterName, Decl(classUsedBeforeInitializedVariables.ts, 22, 6))
>_ : Symbol(_, Decl(classUsedBeforeInitializedVariables.ts, 25, 49))
>withinObjectLiteralSetterName : Symbol(Test.withinObjectLiteralSetterName, Decl(classUsedBeforeInitializedVariables.ts, 28, 6))
>_ : Symbol(_, Decl(classUsedBeforeInitializedVariables.ts, 31, 49))
};
withinClassDeclarationExtension: any = (class extends this.withinClassDeclarationExtension { });
>withinClassDeclarationExtension : Symbol(Test.withinClassDeclarationExtension, Decl(classUsedBeforeInitializedVariables.ts, 26, 6))
>this.withinClassDeclarationExtension : Symbol(Test.withinClassDeclarationExtension, Decl(classUsedBeforeInitializedVariables.ts, 26, 6))
>withinClassDeclarationExtension : Symbol(Test.withinClassDeclarationExtension, Decl(classUsedBeforeInitializedVariables.ts, 32, 6))
>this.withinClassDeclarationExtension : Symbol(Test.withinClassDeclarationExtension, Decl(classUsedBeforeInitializedVariables.ts, 32, 6))
>this : Symbol(Test, Decl(classUsedBeforeInitializedVariables.ts, 0, 0))
>withinClassDeclarationExtension : Symbol(Test.withinClassDeclarationExtension, Decl(classUsedBeforeInitializedVariables.ts, 26, 6))
>withinClassDeclarationExtension : Symbol(Test.withinClassDeclarationExtension, Decl(classUsedBeforeInitializedVariables.ts, 32, 6))
fromOptional = this.p5;
>fromOptional : Symbol(Test.fromOptional, Decl(classUsedBeforeInitializedVariables.ts, 34, 100))
>this.p5 : Symbol(Test.p5, Decl(classUsedBeforeInitializedVariables.ts, 4, 11))
>this : Symbol(Test, Decl(classUsedBeforeInitializedVariables.ts, 0, 0))
>p5 : Symbol(Test.p5, Decl(classUsedBeforeInitializedVariables.ts, 4, 11))
// These error cases are ignored (not checked by control flow analysis)
assignedByArrowFunction: any = (() => this.assignedByFunction)();
>assignedByArrowFunction : Symbol(Test.assignedByArrowFunction, Decl(classUsedBeforeInitializedVariables.ts, 28, 100))
>this.assignedByFunction : Symbol(Test.assignedByFunction, Decl(classUsedBeforeInitializedVariables.ts, 32, 69))
>assignedByArrowFunction : Symbol(Test.assignedByArrowFunction, Decl(classUsedBeforeInitializedVariables.ts, 36, 27))
>this.assignedByFunction : Symbol(Test.assignedByFunction, Decl(classUsedBeforeInitializedVariables.ts, 40, 69))
>this : Symbol(Test, Decl(classUsedBeforeInitializedVariables.ts, 0, 0))
>assignedByFunction : Symbol(Test.assignedByFunction, Decl(classUsedBeforeInitializedVariables.ts, 32, 69))
>assignedByFunction : Symbol(Test.assignedByFunction, Decl(classUsedBeforeInitializedVariables.ts, 40, 69))
assignedByFunction: any = (function () {
>assignedByFunction : Symbol(Test.assignedByFunction, Decl(classUsedBeforeInitializedVariables.ts, 32, 69))
>assignedByFunction : Symbol(Test.assignedByFunction, Decl(classUsedBeforeInitializedVariables.ts, 40, 69))
return this.assignedByFunction;
})();

View file

@ -22,6 +22,27 @@ class Test {
>p4 : number
>0 : 0
p5?: number;
>p5 : number
p6?: string;
>p6 : string
p7 = {
>p7 : { hello: string; }
>{ hello: (this.p6 = "string"), } : { hello: string; }
hello: (this.p6 = "string"),
>hello : string
>(this.p6 = "string") : "string"
>this.p6 = "string" : "string"
>this.p6 : string
>this : this
>p6 : string
>"string" : "string"
};
directlyAssigned: any = this.directlyAssigned;
>directlyAssigned : any
>this.directlyAssigned : any
@ -95,6 +116,12 @@ class Test {
>this : this
>withinClassDeclarationExtension : any
fromOptional = this.p5;
>fromOptional : number
>this.p5 : number
>this : this
>p5 : number
// These error cases are ignored (not checked by control flow analysis)
assignedByArrowFunction: any = (() => this.assignedByFunction)();

View file

@ -5,6 +5,12 @@ class Test {
p2 = this.p1;
p3 = this.p4;
p4 = 0;
p5?: number;
p6?: string;
p7 = {
hello: (this.p6 = "string"),
};
directlyAssigned: any = this.directlyAssigned;
@ -30,6 +36,8 @@ class Test {
withinClassDeclarationExtension: any = (class extends this.withinClassDeclarationExtension { });
fromOptional = this.p5;
// These error cases are ignored (not checked by control flow analysis)
assignedByArrowFunction: any = (() => this.assignedByFunction)();