Skip to content

Commit 38da7c6

Browse files
author
Josh Goldberg
authored
Disabled 'used before initialization' error for optional properties (microsoft#43100)
* Disabled 'used before initialization' error for optional properties * Expanded tests to include code snippet from issue
1 parent f9b35cd commit 38da7c6

6 files changed

+120
-37
lines changed

src/compiler/checker.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11936,6 +11936,10 @@ namespace ts {
1193611936
return false;
1193711937
}
1193811938

11939+
function isOptionalPropertyDeclaration(node: Declaration) {
11940+
return isPropertyDeclaration(node) && node.questionToken;
11941+
}
11942+
1193911943
function isOptionalJSDocPropertyLikeTag(node: Node): node is JSDocPropertyLikeTag {
1194011944
if (!isJSDocPropertyLikeTag(node)) {
1194111945
return false;
@@ -27115,6 +27119,7 @@ namespace ts {
2711527119
let diagnosticMessage;
2711627120
const declarationName = idText(right);
2711727121
if (isInPropertyInitializer(node)
27122+
&& !isOptionalPropertyDeclaration(valueDeclaration)
2711827123
&& !(isAccessExpression(node) && isAccessExpression(node.expression))
2711927124
&& !isBlockScopedNameDeclaredBeforeUse(valueDeclaration, right)
2712027125
&& (compilerOptions.useDefineForClassFields || !isPropertyDeclaredInAncestorClass(prop))) {

tests/baselines/reference/classUsedBeforeInitializedVariables.errors.txt

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
tests/cases/compiler/classUsedBeforeInitializedVariables.ts(4,15): error TS2729: Property 'p4' is used before its initialization.
2-
tests/cases/compiler/classUsedBeforeInitializedVariables.ts(7,34): error TS2729: Property 'directlyAssigned' is used before its initialization.
3-
tests/cases/compiler/classUsedBeforeInitializedVariables.ts(16,15): error TS2729: Property 'withinObjectLiteral' is used before its initialization.
4-
tests/cases/compiler/classUsedBeforeInitializedVariables.ts(20,19): error TS2729: Property 'withinObjectLiteralGetterName' is used before its initialization.
5-
tests/cases/compiler/classUsedBeforeInitializedVariables.ts(26,19): error TS2729: Property 'withinObjectLiteralSetterName' is used before its initialization.
6-
tests/cases/compiler/classUsedBeforeInitializedVariables.ts(29,64): error TS2729: Property 'withinClassDeclarationExtension' is used before its initialization.
2+
tests/cases/compiler/classUsedBeforeInitializedVariables.ts(13,34): error TS2729: Property 'directlyAssigned' is used before its initialization.
3+
tests/cases/compiler/classUsedBeforeInitializedVariables.ts(22,15): error TS2729: Property 'withinObjectLiteral' is used before its initialization.
4+
tests/cases/compiler/classUsedBeforeInitializedVariables.ts(26,19): error TS2729: Property 'withinObjectLiteralGetterName' is used before its initialization.
5+
tests/cases/compiler/classUsedBeforeInitializedVariables.ts(32,19): error TS2729: Property 'withinObjectLiteralSetterName' is used before its initialization.
6+
tests/cases/compiler/classUsedBeforeInitializedVariables.ts(35,64): error TS2729: Property 'withinClassDeclarationExtension' is used before its initialization.
77

88

99
==== tests/cases/compiler/classUsedBeforeInitializedVariables.ts (6 errors) ====
@@ -15,11 +15,17 @@ tests/cases/compiler/classUsedBeforeInitializedVariables.ts(29,64): error TS2729
1515
!!! error TS2729: Property 'p4' is used before its initialization.
1616
!!! related TS2728 tests/cases/compiler/classUsedBeforeInitializedVariables.ts:5:5: 'p4' is declared here.
1717
p4 = 0;
18+
p5?: number;
19+
20+
p6?: string;
21+
p7 = {
22+
hello: (this.p6 = "string"),
23+
};
1824

1925
directlyAssigned: any = this.directlyAssigned;
2026
~~~~~~~~~~~~~~~~
2127
!!! error TS2729: Property 'directlyAssigned' is used before its initialization.
22-
!!! related TS2728 tests/cases/compiler/classUsedBeforeInitializedVariables.ts:7:5: 'directlyAssigned' is declared here.
28+
!!! related TS2728 tests/cases/compiler/classUsedBeforeInitializedVariables.ts:13:5: 'directlyAssigned' is declared here.
2329

2430
withinArrowFunction: any = () => this.withinArrowFunction;
2531

@@ -31,14 +37,14 @@ tests/cases/compiler/classUsedBeforeInitializedVariables.ts(29,64): error TS2729
3137
[this.withinObjectLiteral]: true,
3238
~~~~~~~~~~~~~~~~~~~
3339
!!! error TS2729: Property 'withinObjectLiteral' is used before its initialization.
34-
!!! related TS2728 tests/cases/compiler/classUsedBeforeInitializedVariables.ts:15:5: 'withinObjectLiteral' is declared here.
40+
!!! related TS2728 tests/cases/compiler/classUsedBeforeInitializedVariables.ts:21:5: 'withinObjectLiteral' is declared here.
3541
};
3642

3743
withinObjectLiteralGetterName: any = {
3844
get [this.withinObjectLiteralGetterName]() {
3945
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4046
!!! error TS2729: Property 'withinObjectLiteralGetterName' is used before its initialization.
41-
!!! related TS2728 tests/cases/compiler/classUsedBeforeInitializedVariables.ts:19:5: 'withinObjectLiteralGetterName' is declared here.
47+
!!! related TS2728 tests/cases/compiler/classUsedBeforeInitializedVariables.ts:25:5: 'withinObjectLiteralGetterName' is declared here.
4248
return true;
4349
}
4450
};
@@ -47,13 +53,15 @@ tests/cases/compiler/classUsedBeforeInitializedVariables.ts(29,64): error TS2729
4753
set [this.withinObjectLiteralSetterName](_: any) {}
4854
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4955
!!! error TS2729: Property 'withinObjectLiteralSetterName' is used before its initialization.
50-
!!! related TS2728 tests/cases/compiler/classUsedBeforeInitializedVariables.ts:25:5: 'withinObjectLiteralSetterName' is declared here.
56+
!!! related TS2728 tests/cases/compiler/classUsedBeforeInitializedVariables.ts:31:5: 'withinObjectLiteralSetterName' is declared here.
5157
};
5258

5359
withinClassDeclarationExtension: any = (class extends this.withinClassDeclarationExtension { });
5460
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5561
!!! error TS2729: Property 'withinClassDeclarationExtension' is used before its initialization.
56-
!!! related TS2728 tests/cases/compiler/classUsedBeforeInitializedVariables.ts:29:5: 'withinClassDeclarationExtension' is declared here.
62+
!!! related TS2728 tests/cases/compiler/classUsedBeforeInitializedVariables.ts:35:5: 'withinClassDeclarationExtension' is declared here.
63+
64+
fromOptional = this.p5;
5765

5866
// These error cases are ignored (not checked by control flow analysis)
5967

tests/baselines/reference/classUsedBeforeInitializedVariables.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ class Test {
44
p2 = this.p1;
55
p3 = this.p4;
66
p4 = 0;
7+
p5?: number;
8+
9+
p6?: string;
10+
p7 = {
11+
hello: (this.p6 = "string"),
12+
};
713

814
directlyAssigned: any = this.directlyAssigned;
915

@@ -29,6 +35,8 @@ class Test {
2935

3036
withinClassDeclarationExtension: any = (class extends this.withinClassDeclarationExtension { });
3137

38+
fromOptional = this.p5;
39+
3240
// These error cases are ignored (not checked by control flow analysis)
3341

3442
assignedByArrowFunction: any = (() => this.assignedByFunction)();
@@ -63,6 +71,9 @@ var Test = /** @class */ (function () {
6371
this.p2 = this.p1;
6472
this.p3 = this.p4;
6573
this.p4 = 0;
74+
this.p7 = {
75+
hello: (this.p6 = "string"),
76+
};
6677
this.directlyAssigned = this.directlyAssigned;
6778
this.withinArrowFunction = function () { return _this.withinArrowFunction; };
6879
this.withinFunction = function () {
@@ -94,6 +105,7 @@ var Test = /** @class */ (function () {
94105
}
95106
return class_1;
96107
}(this.withinClassDeclarationExtension)));
108+
this.fromOptional = this.p5;
97109
// These error cases are ignored (not checked by control flow analysis)
98110
this.assignedByArrowFunction = (function () { return _this.assignedByFunction; })();
99111
this.assignedByFunction = (function () {

tests/baselines/reference/classUsedBeforeInitializedVariables.symbols

Lines changed: 50 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -20,76 +20,99 @@ class Test {
2020
p4 = 0;
2121
>p4 : Symbol(Test.p4, Decl(classUsedBeforeInitializedVariables.ts, 3, 17))
2222

23+
p5?: number;
24+
>p5 : Symbol(Test.p5, Decl(classUsedBeforeInitializedVariables.ts, 4, 11))
25+
26+
p6?: string;
27+
>p6 : Symbol(Test.p6, Decl(classUsedBeforeInitializedVariables.ts, 5, 16))
28+
29+
p7 = {
30+
>p7 : Symbol(Test.p7, Decl(classUsedBeforeInitializedVariables.ts, 7, 16))
31+
32+
hello: (this.p6 = "string"),
33+
>hello : Symbol(hello, Decl(classUsedBeforeInitializedVariables.ts, 8, 10))
34+
>this.p6 : Symbol(Test.p6, Decl(classUsedBeforeInitializedVariables.ts, 5, 16))
35+
>this : Symbol(Test, Decl(classUsedBeforeInitializedVariables.ts, 0, 0))
36+
>p6 : Symbol(Test.p6, Decl(classUsedBeforeInitializedVariables.ts, 5, 16))
37+
38+
};
39+
2340
directlyAssigned: any = this.directlyAssigned;
24-
>directlyAssigned : Symbol(Test.directlyAssigned, Decl(classUsedBeforeInitializedVariables.ts, 4, 11))
25-
>this.directlyAssigned : Symbol(Test.directlyAssigned, Decl(classUsedBeforeInitializedVariables.ts, 4, 11))
41+
>directlyAssigned : Symbol(Test.directlyAssigned, Decl(classUsedBeforeInitializedVariables.ts, 10, 6))
42+
>this.directlyAssigned : Symbol(Test.directlyAssigned, Decl(classUsedBeforeInitializedVariables.ts, 10, 6))
2643
>this : Symbol(Test, Decl(classUsedBeforeInitializedVariables.ts, 0, 0))
27-
>directlyAssigned : Symbol(Test.directlyAssigned, Decl(classUsedBeforeInitializedVariables.ts, 4, 11))
44+
>directlyAssigned : Symbol(Test.directlyAssigned, Decl(classUsedBeforeInitializedVariables.ts, 10, 6))
2845

2946
withinArrowFunction: any = () => this.withinArrowFunction;
30-
>withinArrowFunction : Symbol(Test.withinArrowFunction, Decl(classUsedBeforeInitializedVariables.ts, 6, 50))
31-
>this.withinArrowFunction : Symbol(Test.withinArrowFunction, Decl(classUsedBeforeInitializedVariables.ts, 6, 50))
47+
>withinArrowFunction : Symbol(Test.withinArrowFunction, Decl(classUsedBeforeInitializedVariables.ts, 12, 50))
48+
>this.withinArrowFunction : Symbol(Test.withinArrowFunction, Decl(classUsedBeforeInitializedVariables.ts, 12, 50))
3249
>this : Symbol(Test, Decl(classUsedBeforeInitializedVariables.ts, 0, 0))
33-
>withinArrowFunction : Symbol(Test.withinArrowFunction, Decl(classUsedBeforeInitializedVariables.ts, 6, 50))
50+
>withinArrowFunction : Symbol(Test.withinArrowFunction, Decl(classUsedBeforeInitializedVariables.ts, 12, 50))
3451

3552
withinFunction: any = function () {
36-
>withinFunction : Symbol(Test.withinFunction, Decl(classUsedBeforeInitializedVariables.ts, 8, 62))
53+
>withinFunction : Symbol(Test.withinFunction, Decl(classUsedBeforeInitializedVariables.ts, 14, 62))
3754

3855
return this.withinFunction;
3956
};
4057

4158
withinObjectLiteral: any = {
42-
>withinObjectLiteral : Symbol(Test.withinObjectLiteral, Decl(classUsedBeforeInitializedVariables.ts, 12, 6))
59+
>withinObjectLiteral : Symbol(Test.withinObjectLiteral, Decl(classUsedBeforeInitializedVariables.ts, 18, 6))
4360

4461
[this.withinObjectLiteral]: true,
45-
>[this.withinObjectLiteral] : Symbol([this.withinObjectLiteral], Decl(classUsedBeforeInitializedVariables.ts, 14, 32))
46-
>this.withinObjectLiteral : Symbol(Test.withinObjectLiteral, Decl(classUsedBeforeInitializedVariables.ts, 12, 6))
62+
>[this.withinObjectLiteral] : Symbol([this.withinObjectLiteral], Decl(classUsedBeforeInitializedVariables.ts, 20, 32))
63+
>this.withinObjectLiteral : Symbol(Test.withinObjectLiteral, Decl(classUsedBeforeInitializedVariables.ts, 18, 6))
4764
>this : Symbol(Test, Decl(classUsedBeforeInitializedVariables.ts, 0, 0))
48-
>withinObjectLiteral : Symbol(Test.withinObjectLiteral, Decl(classUsedBeforeInitializedVariables.ts, 12, 6))
65+
>withinObjectLiteral : Symbol(Test.withinObjectLiteral, Decl(classUsedBeforeInitializedVariables.ts, 18, 6))
4966

5067
};
5168

5269
withinObjectLiteralGetterName: any = {
53-
>withinObjectLiteralGetterName : Symbol(Test.withinObjectLiteralGetterName, Decl(classUsedBeforeInitializedVariables.ts, 16, 6))
70+
>withinObjectLiteralGetterName : Symbol(Test.withinObjectLiteralGetterName, Decl(classUsedBeforeInitializedVariables.ts, 22, 6))
5471

5572
get [this.withinObjectLiteralGetterName]() {
56-
>[this.withinObjectLiteralGetterName] : Symbol([this.withinObjectLiteralGetterName], Decl(classUsedBeforeInitializedVariables.ts, 18, 42))
57-
>this.withinObjectLiteralGetterName : Symbol(Test.withinObjectLiteralGetterName, Decl(classUsedBeforeInitializedVariables.ts, 16, 6))
73+
>[this.withinObjectLiteralGetterName] : Symbol([this.withinObjectLiteralGetterName], Decl(classUsedBeforeInitializedVariables.ts, 24, 42))
74+
>this.withinObjectLiteralGetterName : Symbol(Test.withinObjectLiteralGetterName, Decl(classUsedBeforeInitializedVariables.ts, 22, 6))
5875
>this : Symbol(Test, Decl(classUsedBeforeInitializedVariables.ts, 0, 0))
59-
>withinObjectLiteralGetterName : Symbol(Test.withinObjectLiteralGetterName, Decl(classUsedBeforeInitializedVariables.ts, 16, 6))
76+
>withinObjectLiteralGetterName : Symbol(Test.withinObjectLiteralGetterName, Decl(classUsedBeforeInitializedVariables.ts, 22, 6))
6077

6178
return true;
6279
}
6380
};
6481

6582
withinObjectLiteralSetterName: any = {
66-
>withinObjectLiteralSetterName : Symbol(Test.withinObjectLiteralSetterName, Decl(classUsedBeforeInitializedVariables.ts, 22, 6))
83+
>withinObjectLiteralSetterName : Symbol(Test.withinObjectLiteralSetterName, Decl(classUsedBeforeInitializedVariables.ts, 28, 6))
6784

6885
set [this.withinObjectLiteralSetterName](_: any) {}
69-
>[this.withinObjectLiteralSetterName] : Symbol([this.withinObjectLiteralSetterName], Decl(classUsedBeforeInitializedVariables.ts, 24, 42))
70-
>this.withinObjectLiteralSetterName : Symbol(Test.withinObjectLiteralSetterName, Decl(classUsedBeforeInitializedVariables.ts, 22, 6))
86+
>[this.withinObjectLiteralSetterName] : Symbol([this.withinObjectLiteralSetterName], Decl(classUsedBeforeInitializedVariables.ts, 30, 42))
87+
>this.withinObjectLiteralSetterName : Symbol(Test.withinObjectLiteralSetterName, Decl(classUsedBeforeInitializedVariables.ts, 28, 6))
7188
>this : Symbol(Test, Decl(classUsedBeforeInitializedVariables.ts, 0, 0))
72-
>withinObjectLiteralSetterName : Symbol(Test.withinObjectLiteralSetterName, Decl(classUsedBeforeInitializedVariables.ts, 22, 6))
73-
>_ : Symbol(_, Decl(classUsedBeforeInitializedVariables.ts, 25, 49))
89+
>withinObjectLiteralSetterName : Symbol(Test.withinObjectLiteralSetterName, Decl(classUsedBeforeInitializedVariables.ts, 28, 6))
90+
>_ : Symbol(_, Decl(classUsedBeforeInitializedVariables.ts, 31, 49))
7491

7592
};
7693

7794
withinClassDeclarationExtension: any = (class extends this.withinClassDeclarationExtension { });
78-
>withinClassDeclarationExtension : Symbol(Test.withinClassDeclarationExtension, Decl(classUsedBeforeInitializedVariables.ts, 26, 6))
79-
>this.withinClassDeclarationExtension : Symbol(Test.withinClassDeclarationExtension, Decl(classUsedBeforeInitializedVariables.ts, 26, 6))
95+
>withinClassDeclarationExtension : Symbol(Test.withinClassDeclarationExtension, Decl(classUsedBeforeInitializedVariables.ts, 32, 6))
96+
>this.withinClassDeclarationExtension : Symbol(Test.withinClassDeclarationExtension, Decl(classUsedBeforeInitializedVariables.ts, 32, 6))
97+
>this : Symbol(Test, Decl(classUsedBeforeInitializedVariables.ts, 0, 0))
98+
>withinClassDeclarationExtension : Symbol(Test.withinClassDeclarationExtension, Decl(classUsedBeforeInitializedVariables.ts, 32, 6))
99+
100+
fromOptional = this.p5;
101+
>fromOptional : Symbol(Test.fromOptional, Decl(classUsedBeforeInitializedVariables.ts, 34, 100))
102+
>this.p5 : Symbol(Test.p5, Decl(classUsedBeforeInitializedVariables.ts, 4, 11))
80103
>this : Symbol(Test, Decl(classUsedBeforeInitializedVariables.ts, 0, 0))
81-
>withinClassDeclarationExtension : Symbol(Test.withinClassDeclarationExtension, Decl(classUsedBeforeInitializedVariables.ts, 26, 6))
104+
>p5 : Symbol(Test.p5, Decl(classUsedBeforeInitializedVariables.ts, 4, 11))
82105

83106
// These error cases are ignored (not checked by control flow analysis)
84107

85108
assignedByArrowFunction: any = (() => this.assignedByFunction)();
86-
>assignedByArrowFunction : Symbol(Test.assignedByArrowFunction, Decl(classUsedBeforeInitializedVariables.ts, 28, 100))
87-
>this.assignedByFunction : Symbol(Test.assignedByFunction, Decl(classUsedBeforeInitializedVariables.ts, 32, 69))
109+
>assignedByArrowFunction : Symbol(Test.assignedByArrowFunction, Decl(classUsedBeforeInitializedVariables.ts, 36, 27))
110+
>this.assignedByFunction : Symbol(Test.assignedByFunction, Decl(classUsedBeforeInitializedVariables.ts, 40, 69))
88111
>this : Symbol(Test, Decl(classUsedBeforeInitializedVariables.ts, 0, 0))
89-
>assignedByFunction : Symbol(Test.assignedByFunction, Decl(classUsedBeforeInitializedVariables.ts, 32, 69))
112+
>assignedByFunction : Symbol(Test.assignedByFunction, Decl(classUsedBeforeInitializedVariables.ts, 40, 69))
90113

91114
assignedByFunction: any = (function () {
92-
>assignedByFunction : Symbol(Test.assignedByFunction, Decl(classUsedBeforeInitializedVariables.ts, 32, 69))
115+
>assignedByFunction : Symbol(Test.assignedByFunction, Decl(classUsedBeforeInitializedVariables.ts, 40, 69))
93116

94117
return this.assignedByFunction;
95118
})();

tests/baselines/reference/classUsedBeforeInitializedVariables.types

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,27 @@ class Test {
2222
>p4 : number
2323
>0 : 0
2424

25+
p5?: number;
26+
>p5 : number
27+
28+
p6?: string;
29+
>p6 : string
30+
31+
p7 = {
32+
>p7 : { hello: string; }
33+
>{ hello: (this.p6 = "string"), } : { hello: string; }
34+
35+
hello: (this.p6 = "string"),
36+
>hello : string
37+
>(this.p6 = "string") : "string"
38+
>this.p6 = "string" : "string"
39+
>this.p6 : string
40+
>this : this
41+
>p6 : string
42+
>"string" : "string"
43+
44+
};
45+
2546
directlyAssigned: any = this.directlyAssigned;
2647
>directlyAssigned : any
2748
>this.directlyAssigned : any
@@ -95,6 +116,12 @@ class Test {
95116
>this : this
96117
>withinClassDeclarationExtension : any
97118

119+
fromOptional = this.p5;
120+
>fromOptional : number
121+
>this.p5 : number
122+
>this : this
123+
>p5 : number
124+
98125
// These error cases are ignored (not checked by control flow analysis)
99126

100127
assignedByArrowFunction: any = (() => this.assignedByFunction)();

tests/cases/compiler/classUsedBeforeInitializedVariables.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ class Test {
55
p2 = this.p1;
66
p3 = this.p4;
77
p4 = 0;
8+
p5?: number;
9+
10+
p6?: string;
11+
p7 = {
12+
hello: (this.p6 = "string"),
13+
};
814

915
directlyAssigned: any = this.directlyAssigned;
1016

@@ -30,6 +36,8 @@ class Test {
3036

3137
withinClassDeclarationExtension: any = (class extends this.withinClassDeclarationExtension { });
3238

39+
fromOptional = this.p5;
40+
3341
// These error cases are ignored (not checked by control flow analysis)
3442

3543
assignedByArrowFunction: any = (() => this.assignedByFunction)();

0 commit comments

Comments
 (0)