Error on this.xxx access of previously declared but uninitialized property (#38030)
* Error on this.xxx access of previously declared but uninitialized property * Add tests * Accept new baselines
This commit is contained in:
parent
9d8a70c809
commit
16d2eb7075
|
@ -1364,7 +1364,7 @@ namespace ts {
|
|||
return sourceFiles.indexOf(declarationFile) <= sourceFiles.indexOf(useFile);
|
||||
}
|
||||
|
||||
if (declaration.pos <= usage.pos) {
|
||||
if (declaration.pos <= usage.pos && !(isPropertyDeclaration(declaration) && isThisProperty(usage.parent) && !declaration.initializer && !declaration.exclamationToken)) {
|
||||
// declaration is before usage
|
||||
if (declaration.kind === SyntaxKind.BindingElement) {
|
||||
// still might be illegal if declaration and usage are both binding elements (eg var [a = b, b = b] = [1, 2])
|
||||
|
|
|
@ -2,10 +2,11 @@ tests/cases/compiler/abstractPropertyInConstructor.ts(4,24): error TS2715: Abstr
|
|||
tests/cases/compiler/abstractPropertyInConstructor.ts(7,18): error TS2715: Abstract property 'prop' in class 'AbstractClass' cannot be accessed in the constructor.
|
||||
tests/cases/compiler/abstractPropertyInConstructor.ts(9,14): error TS2715: Abstract property 'cb' in class 'AbstractClass' cannot be accessed in the constructor.
|
||||
tests/cases/compiler/abstractPropertyInConstructor.ts(25,18): error TS2715: Abstract property 'prop' in class 'AbstractClass' cannot be accessed in the constructor.
|
||||
tests/cases/compiler/abstractPropertyInConstructor.ts(25,18): error TS2729: Property 'prop' is used before its initialization.
|
||||
tests/cases/compiler/abstractPropertyInConstructor.ts(39,22): error TS2715: Abstract property 'prop' in class 'AbstractClass' cannot be accessed in the constructor.
|
||||
|
||||
|
||||
==== tests/cases/compiler/abstractPropertyInConstructor.ts (5 errors) ====
|
||||
==== tests/cases/compiler/abstractPropertyInConstructor.ts (6 errors) ====
|
||||
abstract class AbstractClass {
|
||||
constructor(str: string, other: AbstractClass) {
|
||||
this.method(parseInt(str));
|
||||
|
@ -39,6 +40,9 @@ tests/cases/compiler/abstractPropertyInConstructor.ts(39,22): error TS2715: Abst
|
|||
other = this.prop;
|
||||
~~~~
|
||||
!!! error TS2715: Abstract property 'prop' in class 'AbstractClass' cannot be accessed in the constructor.
|
||||
~~~~
|
||||
!!! error TS2729: Property 'prop' is used before its initialization.
|
||||
!!! related TS2728 tests/cases/compiler/abstractPropertyInConstructor.ts:20:14: 'prop' is declared here.
|
||||
fn = () => this.prop;
|
||||
|
||||
method2() {
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
tests/cases/compiler/initializerWithThisPropertyAccess.ts(3,14): error TS2729: Property 'a' is used before its initialization.
|
||||
tests/cases/compiler/initializerWithThisPropertyAccess.ts(24,29): error TS2729: Property 'bar' is used before its initialization.
|
||||
|
||||
|
||||
==== tests/cases/compiler/initializerWithThisPropertyAccess.ts (2 errors) ====
|
||||
class A {
|
||||
a: number;
|
||||
b = this.a; // Error
|
||||
~
|
||||
!!! error TS2729: Property 'a' is used before its initialization.
|
||||
!!! related TS2728 tests/cases/compiler/initializerWithThisPropertyAccess.ts:2:5: 'a' is declared here.
|
||||
c = () => this.a;
|
||||
d = (new A()).a;
|
||||
constructor() {
|
||||
this.a = 1;
|
||||
}
|
||||
}
|
||||
|
||||
class B extends A {
|
||||
x = this.a;
|
||||
}
|
||||
|
||||
class C {
|
||||
a!: number;
|
||||
b = this.a;
|
||||
}
|
||||
|
||||
// Repro from #37979
|
||||
|
||||
class Foo {
|
||||
private bar: Bar;
|
||||
readonly barProp = this.bar.prop;
|
||||
~~~
|
||||
!!! error TS2729: Property 'bar' is used before its initialization.
|
||||
!!! related TS2728 tests/cases/compiler/initializerWithThisPropertyAccess.ts:23:13: 'bar' is declared here.
|
||||
constructor() {
|
||||
this.bar = new Bar();
|
||||
}
|
||||
}
|
||||
|
||||
class Bar {
|
||||
readonly prop = false;
|
||||
}
|
||||
|
114
tests/baselines/reference/initializerWithThisPropertyAccess.js
Normal file
114
tests/baselines/reference/initializerWithThisPropertyAccess.js
Normal file
|
@ -0,0 +1,114 @@
|
|||
//// [initializerWithThisPropertyAccess.ts]
|
||||
class A {
|
||||
a: number;
|
||||
b = this.a; // Error
|
||||
c = () => this.a;
|
||||
d = (new A()).a;
|
||||
constructor() {
|
||||
this.a = 1;
|
||||
}
|
||||
}
|
||||
|
||||
class B extends A {
|
||||
x = this.a;
|
||||
}
|
||||
|
||||
class C {
|
||||
a!: number;
|
||||
b = this.a;
|
||||
}
|
||||
|
||||
// Repro from #37979
|
||||
|
||||
class Foo {
|
||||
private bar: Bar;
|
||||
readonly barProp = this.bar.prop;
|
||||
constructor() {
|
||||
this.bar = new Bar();
|
||||
}
|
||||
}
|
||||
|
||||
class Bar {
|
||||
readonly prop = false;
|
||||
}
|
||||
|
||||
|
||||
//// [initializerWithThisPropertyAccess.js]
|
||||
"use strict";
|
||||
var __extends = (this && this.__extends) || (function () {
|
||||
var extendStatics = function (d, b) {
|
||||
extendStatics = Object.setPrototypeOf ||
|
||||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
||||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
|
||||
return extendStatics(d, b);
|
||||
};
|
||||
return function (d, b) {
|
||||
extendStatics(d, b);
|
||||
function __() { this.constructor = d; }
|
||||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
||||
};
|
||||
})();
|
||||
var A = /** @class */ (function () {
|
||||
function A() {
|
||||
var _this = this;
|
||||
this.b = this.a; // Error
|
||||
this.c = function () { return _this.a; };
|
||||
this.d = (new A()).a;
|
||||
this.a = 1;
|
||||
}
|
||||
return A;
|
||||
}());
|
||||
var B = /** @class */ (function (_super) {
|
||||
__extends(B, _super);
|
||||
function B() {
|
||||
var _this = _super !== null && _super.apply(this, arguments) || this;
|
||||
_this.x = _this.a;
|
||||
return _this;
|
||||
}
|
||||
return B;
|
||||
}(A));
|
||||
var C = /** @class */ (function () {
|
||||
function C() {
|
||||
this.b = this.a;
|
||||
}
|
||||
return C;
|
||||
}());
|
||||
// Repro from #37979
|
||||
var Foo = /** @class */ (function () {
|
||||
function Foo() {
|
||||
this.barProp = this.bar.prop;
|
||||
this.bar = new Bar();
|
||||
}
|
||||
return Foo;
|
||||
}());
|
||||
var Bar = /** @class */ (function () {
|
||||
function Bar() {
|
||||
this.prop = false;
|
||||
}
|
||||
return Bar;
|
||||
}());
|
||||
|
||||
|
||||
//// [initializerWithThisPropertyAccess.d.ts]
|
||||
declare class A {
|
||||
a: number;
|
||||
b: number;
|
||||
c: () => number;
|
||||
d: number;
|
||||
constructor();
|
||||
}
|
||||
declare class B extends A {
|
||||
x: number;
|
||||
}
|
||||
declare class C {
|
||||
a: number;
|
||||
b: number;
|
||||
}
|
||||
declare class Foo {
|
||||
private bar;
|
||||
readonly barProp = false;
|
||||
constructor();
|
||||
}
|
||||
declare class Bar {
|
||||
readonly prop = false;
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
=== tests/cases/compiler/initializerWithThisPropertyAccess.ts ===
|
||||
class A {
|
||||
>A : Symbol(A, Decl(initializerWithThisPropertyAccess.ts, 0, 0))
|
||||
|
||||
a: number;
|
||||
>a : Symbol(A.a, Decl(initializerWithThisPropertyAccess.ts, 0, 9))
|
||||
|
||||
b = this.a; // Error
|
||||
>b : Symbol(A.b, Decl(initializerWithThisPropertyAccess.ts, 1, 14))
|
||||
>this.a : Symbol(A.a, Decl(initializerWithThisPropertyAccess.ts, 0, 9))
|
||||
>this : Symbol(A, Decl(initializerWithThisPropertyAccess.ts, 0, 0))
|
||||
>a : Symbol(A.a, Decl(initializerWithThisPropertyAccess.ts, 0, 9))
|
||||
|
||||
c = () => this.a;
|
||||
>c : Symbol(A.c, Decl(initializerWithThisPropertyAccess.ts, 2, 15))
|
||||
>this.a : Symbol(A.a, Decl(initializerWithThisPropertyAccess.ts, 0, 9))
|
||||
>this : Symbol(A, Decl(initializerWithThisPropertyAccess.ts, 0, 0))
|
||||
>a : Symbol(A.a, Decl(initializerWithThisPropertyAccess.ts, 0, 9))
|
||||
|
||||
d = (new A()).a;
|
||||
>d : Symbol(A.d, Decl(initializerWithThisPropertyAccess.ts, 3, 21))
|
||||
>(new A()).a : Symbol(A.a, Decl(initializerWithThisPropertyAccess.ts, 0, 9))
|
||||
>A : Symbol(A, Decl(initializerWithThisPropertyAccess.ts, 0, 0))
|
||||
>a : Symbol(A.a, Decl(initializerWithThisPropertyAccess.ts, 0, 9))
|
||||
|
||||
constructor() {
|
||||
this.a = 1;
|
||||
>this.a : Symbol(A.a, Decl(initializerWithThisPropertyAccess.ts, 0, 9))
|
||||
>this : Symbol(A, Decl(initializerWithThisPropertyAccess.ts, 0, 0))
|
||||
>a : Symbol(A.a, Decl(initializerWithThisPropertyAccess.ts, 0, 9))
|
||||
}
|
||||
}
|
||||
|
||||
class B extends A {
|
||||
>B : Symbol(B, Decl(initializerWithThisPropertyAccess.ts, 8, 1))
|
||||
>A : Symbol(A, Decl(initializerWithThisPropertyAccess.ts, 0, 0))
|
||||
|
||||
x = this.a;
|
||||
>x : Symbol(B.x, Decl(initializerWithThisPropertyAccess.ts, 10, 19))
|
||||
>this.a : Symbol(A.a, Decl(initializerWithThisPropertyAccess.ts, 0, 9))
|
||||
>this : Symbol(B, Decl(initializerWithThisPropertyAccess.ts, 8, 1))
|
||||
>a : Symbol(A.a, Decl(initializerWithThisPropertyAccess.ts, 0, 9))
|
||||
}
|
||||
|
||||
class C {
|
||||
>C : Symbol(C, Decl(initializerWithThisPropertyAccess.ts, 12, 1))
|
||||
|
||||
a!: number;
|
||||
>a : Symbol(C.a, Decl(initializerWithThisPropertyAccess.ts, 14, 9))
|
||||
|
||||
b = this.a;
|
||||
>b : Symbol(C.b, Decl(initializerWithThisPropertyAccess.ts, 15, 15))
|
||||
>this.a : Symbol(C.a, Decl(initializerWithThisPropertyAccess.ts, 14, 9))
|
||||
>this : Symbol(C, Decl(initializerWithThisPropertyAccess.ts, 12, 1))
|
||||
>a : Symbol(C.a, Decl(initializerWithThisPropertyAccess.ts, 14, 9))
|
||||
}
|
||||
|
||||
// Repro from #37979
|
||||
|
||||
class Foo {
|
||||
>Foo : Symbol(Foo, Decl(initializerWithThisPropertyAccess.ts, 17, 1))
|
||||
|
||||
private bar: Bar;
|
||||
>bar : Symbol(Foo.bar, Decl(initializerWithThisPropertyAccess.ts, 21, 11))
|
||||
>Bar : Symbol(Bar, Decl(initializerWithThisPropertyAccess.ts, 27, 1))
|
||||
|
||||
readonly barProp = this.bar.prop;
|
||||
>barProp : Symbol(Foo.barProp, Decl(initializerWithThisPropertyAccess.ts, 22, 21))
|
||||
>this.bar.prop : Symbol(Bar.prop, Decl(initializerWithThisPropertyAccess.ts, 29, 11))
|
||||
>this.bar : Symbol(Foo.bar, Decl(initializerWithThisPropertyAccess.ts, 21, 11))
|
||||
>this : Symbol(Foo, Decl(initializerWithThisPropertyAccess.ts, 17, 1))
|
||||
>bar : Symbol(Foo.bar, Decl(initializerWithThisPropertyAccess.ts, 21, 11))
|
||||
>prop : Symbol(Bar.prop, Decl(initializerWithThisPropertyAccess.ts, 29, 11))
|
||||
|
||||
constructor() {
|
||||
this.bar = new Bar();
|
||||
>this.bar : Symbol(Foo.bar, Decl(initializerWithThisPropertyAccess.ts, 21, 11))
|
||||
>this : Symbol(Foo, Decl(initializerWithThisPropertyAccess.ts, 17, 1))
|
||||
>bar : Symbol(Foo.bar, Decl(initializerWithThisPropertyAccess.ts, 21, 11))
|
||||
>Bar : Symbol(Bar, Decl(initializerWithThisPropertyAccess.ts, 27, 1))
|
||||
}
|
||||
}
|
||||
|
||||
class Bar {
|
||||
>Bar : Symbol(Bar, Decl(initializerWithThisPropertyAccess.ts, 27, 1))
|
||||
|
||||
readonly prop = false;
|
||||
>prop : Symbol(Bar.prop, Decl(initializerWithThisPropertyAccess.ts, 29, 11))
|
||||
}
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
=== tests/cases/compiler/initializerWithThisPropertyAccess.ts ===
|
||||
class A {
|
||||
>A : A
|
||||
|
||||
a: number;
|
||||
>a : number
|
||||
|
||||
b = this.a; // Error
|
||||
>b : number
|
||||
>this.a : number
|
||||
>this : this
|
||||
>a : number
|
||||
|
||||
c = () => this.a;
|
||||
>c : () => number
|
||||
>() => this.a : () => number
|
||||
>this.a : number
|
||||
>this : this
|
||||
>a : number
|
||||
|
||||
d = (new A()).a;
|
||||
>d : number
|
||||
>(new A()).a : number
|
||||
>(new A()) : A
|
||||
>new A() : A
|
||||
>A : typeof A
|
||||
>a : number
|
||||
|
||||
constructor() {
|
||||
this.a = 1;
|
||||
>this.a = 1 : 1
|
||||
>this.a : number
|
||||
>this : this
|
||||
>a : number
|
||||
>1 : 1
|
||||
}
|
||||
}
|
||||
|
||||
class B extends A {
|
||||
>B : B
|
||||
>A : A
|
||||
|
||||
x = this.a;
|
||||
>x : number
|
||||
>this.a : number
|
||||
>this : this
|
||||
>a : number
|
||||
}
|
||||
|
||||
class C {
|
||||
>C : C
|
||||
|
||||
a!: number;
|
||||
>a : number
|
||||
|
||||
b = this.a;
|
||||
>b : number
|
||||
>this.a : number
|
||||
>this : this
|
||||
>a : number
|
||||
}
|
||||
|
||||
// Repro from #37979
|
||||
|
||||
class Foo {
|
||||
>Foo : Foo
|
||||
|
||||
private bar: Bar;
|
||||
>bar : Bar
|
||||
|
||||
readonly barProp = this.bar.prop;
|
||||
>barProp : false
|
||||
>this.bar.prop : false
|
||||
>this.bar : Bar
|
||||
>this : this
|
||||
>bar : Bar
|
||||
>prop : false
|
||||
|
||||
constructor() {
|
||||
this.bar = new Bar();
|
||||
>this.bar = new Bar() : Bar
|
||||
>this.bar : Bar
|
||||
>this : this
|
||||
>bar : Bar
|
||||
>new Bar() : Bar
|
||||
>Bar : typeof Bar
|
||||
}
|
||||
}
|
||||
|
||||
class Bar {
|
||||
>Bar : Bar
|
||||
|
||||
readonly prop = false;
|
||||
>prop : false
|
||||
>false : false
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
tests/cases/conformance/expressions/identifiers/scopeResolutionIdentifiers.ts(24,14): error TS2729: Property 's' is used before its initialization.
|
||||
|
||||
|
||||
==== tests/cases/conformance/expressions/identifiers/scopeResolutionIdentifiers.ts (1 errors) ====
|
||||
// EveryType used in a nested scope of a different EveryType with the same name, type of the identifier is the one defined in the inner scope
|
||||
|
||||
var s: string;
|
||||
module M1 {
|
||||
export var s: number;
|
||||
var n = s;
|
||||
var n: number;
|
||||
}
|
||||
|
||||
module M2 {
|
||||
var s: number;
|
||||
var n = s;
|
||||
var n: number;
|
||||
}
|
||||
|
||||
function fn() {
|
||||
var s: boolean;
|
||||
var n = s;
|
||||
var n: boolean;
|
||||
}
|
||||
|
||||
class C {
|
||||
s: Date;
|
||||
n = this.s;
|
||||
~
|
||||
!!! error TS2729: Property 's' is used before its initialization.
|
||||
!!! related TS2728 tests/cases/conformance/expressions/identifiers/scopeResolutionIdentifiers.ts:23:5: 's' is declared here.
|
||||
x() {
|
||||
var p = this.n;
|
||||
var p: Date;
|
||||
}
|
||||
}
|
||||
|
||||
module M3 {
|
||||
var s: any;
|
||||
module M4 {
|
||||
var n = s;
|
||||
var n: any;
|
||||
}
|
||||
}
|
||||
|
35
tests/cases/compiler/initializerWithThisPropertyAccess.ts
Normal file
35
tests/cases/compiler/initializerWithThisPropertyAccess.ts
Normal file
|
@ -0,0 +1,35 @@
|
|||
// @strict: true
|
||||
// @declaration: true
|
||||
|
||||
class A {
|
||||
a: number;
|
||||
b = this.a; // Error
|
||||
c = () => this.a;
|
||||
d = (new A()).a;
|
||||
constructor() {
|
||||
this.a = 1;
|
||||
}
|
||||
}
|
||||
|
||||
class B extends A {
|
||||
x = this.a;
|
||||
}
|
||||
|
||||
class C {
|
||||
a!: number;
|
||||
b = this.a;
|
||||
}
|
||||
|
||||
// Repro from #37979
|
||||
|
||||
class Foo {
|
||||
private bar: Bar;
|
||||
readonly barProp = this.bar.prop;
|
||||
constructor() {
|
||||
this.bar = new Bar();
|
||||
}
|
||||
}
|
||||
|
||||
class Bar {
|
||||
readonly prop = false;
|
||||
}
|
Loading…
Reference in a new issue