- Typescript Virtual Method
- Typescript Private Abstract Property
- Typescript Abstract Property For Sale
- Typescript Abstract Property In Constructor
TypeScript has abstract classes, which are classes that have partial implementation of a class and in which other classes can be derived from. They can’t be instantiated directly. TypeScript - Static. ES6 includes static members and so does TypeScript. The static members of a class are accessed using the class name and dot notation, without creating an object e.g. The static members can be defined by using the keyword static. Consider the following example of a class with static property.
TypeScript includes the readonly keyword that makes a property as read-only in the class, type or interface.
Prefix
readonly
is used to make a property as read-only. Read-only members can be accessed outside the class, but their value cannot be changed. Since read-only members cannot be changed outside the class, they either need to be initialized at declaration or initialized inside the class constructor. In the above example, we have the
Employee
class with two properties- empName
and empCode
. Since empCode
is read only, it can be initialized at the time of declaration or in the constructor. If we try to change the value of
empCode
after the object has been initialized, the compiler shows the following compilation error:error TS2540: Cannot assign to empCode' because it is a constant or a read-only property.
An interface can also have readonly member properties.
As you can see above,
empCode
is readonly, so we can assign a value at the time of creating an object but not after wards.Typescript Virtual Method
In the same way you can use
Readonly<T>
to create a readonly type, as shown below.In the above example,
emp1
is declared as Readonly<IEmployee>
and so values cannot be changed once initialized. TypeScript brings full class-based inheritance to JavaScript projects. This works very well, but you may run into some unexpected behavior when setting properties in a subclass and using those properties in the parent constructor.
Here is a simple example that demonstrates the problem:
- MyBaseClass is defined as an abstract class. Like other OOP languages, this means that the class cannot be instantiated directly.
- MySubClass is a concrete subclass of MyBaseClass that can be instantiated.
- New in TypeScript 2.0 is the ability to define properties as abstract, which I have done with string1 and string2. These properties must be set in the subclass, or the transpiler will generate an error.
- The parent class constructor sets the string3 property based on the values of string1 and string2 set in the subclass. Imagine that string3 is a property that will be used by other methods in the base class (not shown in the example code), so it is a valid design choice to set that property in the constructor.
- Finally, the last two lines of code instantiate the class and display string3.
Of course, I expected this code to display “Hello World!”, but in fact it displays “undefined undefined”. Why is that? A look at the transpiled Javascript of the subclass constructor will give us a clue.
As you can see, the subclass properties aren’t set until AFTER the base constructor is called. Ryan Cavanaugh from Microsoft explains:
This is the intended behavior.
Screens 4 2 2 – access your computer remotely. The order of initialization is:
1. The base class initialized properties are initialized
1. The base class initialized properties are initialized
2. The base class constructor runs
3. The derived class initialized properties are initialized
4. The derived class constructor runs
Follow the link for more details on the reasons, but it comes down to the fact that property initialization is inextricably intertwined with the constructor. Alternative approaches have been suggested, but besides breaking existing code, the order above is likely to become part of the EcmaScript (JavaScript) standard.
As an OOP veteran of other languages, I find this behavior unfortunate. By defining a class as abstract, you are in effect saying it is “incomplete“, and it will be completed by its concrete subclasses. These technical restrictions on property initialization and constructors get in the way, but there are things we can do to work around the problem.
Constructor Parameters
Rather than setting properties in the subclass, you can pass values to the base class constructor.
Typescript Private Abstract Property
This works, but stylistically, I don’t like it for an inheritance-based approach. I’d rather have the ability to simply set properties in the subclass, but call it personal preference. There is nothing wrong with this solution.
Constructor Hook Method
Here, I’ve added an initialize() hook method to the constructor that runs before the buildString3() method. This gives the subclass an opportunity to set properties the base class needs at the appropriate time. I’ve declared the initalize() method as abstract, so that it must be implemented in the subclass.
This also works, but it leaves much to be desired. Even though I have declared the initialize() method as abstract, nothing forces the string1 and string2 properties to be set. Notice that I had to remove the abstract keyword from those properties for this to transpile without error. In general, I like the idea of adding hook methods for subclasses to use, but they should be optional. The base class should not depend on them, nor should it be ambiguous about which properties need to be set.
Getters/Setters
As you may have gathered from the above, methods do not suffer from the same constructor timing issues as properties. The base class constructor called into the subclass initialize() method, and it functioned as expected. Likewise, using getter/setter syntax for properties is an option:
Minecraft: story mode a telltale games series (ep 1 7). This is closer to the original vision. Having to use getter syntax is a little wordy for my taste, when all you want to do is return a simple value. You may not mind if you are used to this from other languages.
Move the Code
Finally, my favorite solution is to move the code out of the constructor, which is where the timing issue is. I moved the code into the string3 property with getter syntax. It won’t run until the property is accessed after the object has been constructed, so the timing issue is avoided. I also added a private _string3 property for improved performance, but of course, that is optional.
This solution is the closest the original code. I also like the idea of doing more in the base class, so you can do less in subclasses.
Typescript Abstract Property For Sale
Your mileage may vary depending on your specific scenario, so choose the workaround that works best for you.