What's more, before we ever access a property on this in a constructor body, we have. When a member is marked private, it cannot be accessed from outside of its. The abstract keyword is used to define abstract classes as well as abstract. Oct 15, 2017 - index.ts(11,12): error TS2715: Abstract property 'name' in class 'Animal' cannot be accessed in the constructor. This regression was introduced.
TypeScript Version:
2.7.1
2.7.1
Actual behavior:
After upgrading from [email protected], the following code does not compile anymore:
After upgrading from [email protected], the following code does not compile anymore:
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
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:
When it comes to getters, things behave a little different. Consider the following piece of code:
it produces the following output:
abstract class constructor: a: -1
abstract class constructor: b: 42
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
derived class constructor: b: 42
derived class constructor: c: 43
anywhere else: a: 41
anywhere else: b: 42
anywhere else: c: 43
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 [email protected] 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.
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
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
TypeScript Playground with my example: http://bit.ly/2F3C2xR
Related Issues:
#9230#19005
-->#9230#19005
Inheritance, together with encapsulation and polymorphism, is one of the three primary characteristics of object-oriented programming. Inheritance enables you to create new classes that reuse, extend, and modify the behavior that is defined in other classes. The class whose members are inherited is called the base class, and the class that inherits those members is called the derived class. A derived class can have only one direct base class. However, inheritance is transitive. If ClassC is derived from ClassB, and ClassB is derived from ClassA, ClassC inherits the members declared in ClassB and ClassA.
Note
Structs do not support inheritance, but they can implement interfaces. For more information, see Interfaces.
Conceptually, a derived class is a specialization of the base class. For example, if you have a base class
Animal
, you might have one derived class that is named Mammal
and another derived class that is named Reptile
. A Mammal
is an Animal
, and a Reptile
is an Animal
, but each derived class represents different specializations of the base class.When you define a class to derive from another class, the derived class implicitly gains all the members of the base class, except for its constructors and finalizers. The derived class can thereby reuse the code in the base class without having to re-implement it. In the derived class, you can add more members. In this manner, the derived class extends the functionality of the base class.
The following illustration shows a class
WorkItem
that represents an item of work in some business process. Like all classes, it derives from System.Object and inherits all its methods. WorkItem
adds five members of its own. These include a constructor, because constructors are not inherited. Class ChangeRequest
inherits from WorkItem
and represents a particular kind of work item. ChangeRequest
adds two more members to the members that it inherits from WorkItem
and from Object. It must add its own constructor, and it also adds originalItemID
. Property originalItemID
enables the ChangeRequest
instance to be associated with the original WorkItem
to which the change request applies.The following example shows how the class relationships demonstrated in the previous illustration are expressed in C#. The example also shows how
WorkItem
overrides the virtual method Object.ToString, and how the ChangeRequest
class inherits the WorkItem
implementation of the method.Abstract and Virtual Methods
When a base class declares a method as virtual, a derived class can override the method with its own implementation. If a base class declares a member as abstract, that method must be overridden in any non-abstract class that directly inherits from that class. If a derived class is itself abstract, it inherits abstract members without implementing them. Abstract and virtual members are the basis for polymorphism, which is the second primary characteristic of object-oriented programming. For more information, see Polymorphism.
Abstract Base Classes
You can declare a class as abstract if you want to prevent direct instantiation by using the new keyword. If you do this, the class can be used only if a new class is derived from it. An abstract class can contain one or more method signatures that themselves are declared as abstract. These signatures specify the parameters and return value but have no implementation (method body). An abstract class does not have to contain abstract members; however, if a class does contain an abstract member, the class itself must be declared as abstract. Derived classes that are not abstract themselves must provide the implementation for any abstract methods from an abstract base class. For more information, see Abstract and Sealed Classes and Class Members.
Interfaces
An interface is a reference type that is somewhat similar to an abstract base class that consists of only abstract members. When a class implements an interface, it must provide an implementation for all the members of the interface. A class can implement multiple interfaces even though it can derive from only a single direct base class.
Interfaces are used to define specific capabilities for classes that do not necessarily have an 'is a' relationship. For example, the System.IEquatable<T> interface can be implemented by any class or struct that has to enable client code to determine whether two objects of the type are equivalent (however the type defines equivalence). IEquatable<T> does not imply the same kind of 'is a' relationship that exists between a base class and a derived class (for example, a
Mammal
is an Animal
). For more information, see Interfaces.Preventing Further Derivation
A class can prevent other classes from inheriting from it, or from any of its members, by declaring itself or the member as sealed. For more information, see Abstract and Sealed Classes and Class Members.
Derived Class Hiding of Base Class Members
A derived class can hide base class members by declaring members with the same name and signature. The new modifier can be used to explicitly indicate that the member is not intended to be an override of the base member. The use of new is not required, but a compiler warning will be generated if new is not used. For more information, see Versioning with the Override and New Keywords and Knowing When to Use Override and New Keywords.