TypeScript Version:
2.7.1
Actual behavior:
After upgrading from typescript@2.6.2, the following code does not compile anymore:
abstract class MyClass {
abstract get b(): number;
constructor() {
console.log(this.b);
}
}
class MyDerivedClass extends MyClass {
get b() {
return 42;
}
constructor() {
super();
}
}
TS2715: Abstract property 'b' in class 'MyClass' cannot be accessed in the constructor.
This behaviour is related to #9230 and is totally legit as long as we are talking about 'normal' properties like
abstract class MyClass {
abstract i: number;
constructor() {
console.log(this.i);
}
}
I understand that my i-property would not have been initialized when the constructor executes, as @RyanCavanaugh pointed out here.
Expected behaviour:
When it comes to getters, things behave a little different. Consider the following piece of code:
abstract class MyClass {
a: number = -1;
get b(): number {
return -2;
}
abstract c(): number;
constructor() {
console.log('abstract class constructor: a: ' + this.a);
console.log('abstract class constructor: b: ' + this.b);
console.log('abstract class constructor: c: ' + this.c());
}
}
class MyDerivedClass extends MyClass {
a: number = 41;
get b() {
return 42;
}
c() {
return 43;
}
constructor() {
super();
console.log('derived class constructor: a: ' + this.a);
console.log('derived class constructor: b: ' + this.b);
console.log('derived class constructor: c: ' + this.c());
}
}
const myClass = new MyDerivedClass();
console.log('anywhere else: a: ' + myClass.a);
console.log('anywhere else: b: ' + myClass.b);
console.log('anywhere else: c: ' + myClass.c());
it produces the following output:
abstract class constructor: a: -1
abstract class constructor: b: 42
You might expect b: -2 here, but we already receive the value provided in the derived class.
abstract class constructor: c: 43
derived class constructor: a: 41
derived class constructor: b: 42
derived class constructor: c: 43
anywhere else: a: 41
anywhere else: b: 42
anywhere else: c: 43
As you can see, accessing b in the constructor results in a different behavior than accessing a. While accessing a returns the value specified in MyClass, accessing b already executes the getter specified in MyDerivedClass. In other words, having abstract get b(): number; declared in MyClass would not result in an uninitialized property inside the MyClass-constructor.
Transpiling my example and then removing the b-property from MyClass in the transpiled JS-source still produces the expected output.
Also, accessing the abstract getter while using typescript@2.6.2 resulted in the correct behavior (= executing the getter in my derived class).
Long Story short:
When accessing an abstract property inside a constructor, I would expect TS2715 to be thrown. But when the property is actually encapsulated by a getter, I would expect TS2715 not to be thrown as such code would execute correctly.
Background:
In my case, the value returned by the getter can be understood as a child-class-specific configuration that is required to initialize the super-class correctly. When writing my original piece of code, my intention was to force some future developer to implement this getter in his derived class, so the abstract class can be completly initialized inside its own constructor. Of course this dependency could be passed from the derived-class to the super-class by calling an init-function after constructing the object, as @RyanCavanaugh suggested in his explanation, but I think using the abstract getter is easier as you need to know less about the behavior and usage-instructions of the super-class
Playground Link:
TypeScript Playground with my example: http://bit.ly/2F3C2xR
Related Issues:
#9230 #19005
TypeScript Version:
2.7.1
Actual behavior:
After upgrading from typescript@2.6.2, the following code does not compile anymore:
This behaviour is related to #9230 and is totally legit as long as we are talking about 'normal' properties like
I understand that my
i-property would not have been initialized when the constructor executes, as @RyanCavanaugh pointed out here.Expected behaviour:
When it comes to getters, things behave a little different. Consider the following piece of code:
it produces the following output:
As you can see, accessing
bin the constructor results in a different behavior than accessinga. While accessingareturns the value specified inMyClass, accessingbalready executes the getter specified inMyDerivedClass. In other words, havingabstract get b(): number;declared inMyClasswould not result in an uninitialized property inside theMyClass-constructor.Transpiling my example and then removing the
b-property fromMyClassin the transpiled JS-source still produces the expected output.Also, accessing the abstract getter while using typescript@2.6.2 resulted in the correct behavior (= executing the getter in my derived class).
Long Story short:
When accessing an abstract property inside a constructor, I would expect TS2715 to be thrown. But when the property is actually encapsulated by a getter, I would expect TS2715 not to be thrown as such code would execute correctly.
Background:
In my case, the value returned by the getter can be understood as a child-class-specific configuration that is required to initialize the super-class correctly. When writing my original piece of code, my intention was to force some future developer to implement this getter in his derived class, so the abstract class can be completly initialized inside its own constructor. Of course this dependency could be passed from the derived-class to the super-class by calling an init-function after constructing the object, as @RyanCavanaugh suggested in his explanation, but I think using the abstract getter is easier as you need to know less about the behavior and usage-instructions of the super-class
Playground Link:
TypeScript Playground with my example: http://bit.ly/2F3C2xR
Related Issues:
#9230 #19005