Assume the following Typescript example
class Animal {
public name: string;
constructor() {
console.log(this.name);
}
}
class Snake extends Animal {
public name = 'BeatSSS';
}
let someSnake = new Snake();
Of course, console.log()
logs undefined
. And BeatSSS
was expected.
How can we do things from parent constructor()
with child properties?
Actual ideas:
I like what Jeff and Duncan already have proposed quite a lot. Let me show one more option, though.
abstract class Animal {
constructor(public name: string) {
console.log(this.name);
}
}
class Snake extends Animal { }
let someSnake = new Snake("Snakeeeey!");
Notice a few things here.
Animal
class seems to be indeed an abstract concept. You have an option of either marking it as abstract
or defining it as an interface
, but the latter will not let you have any implementation (including constructor).constructor(public name: string)
.The Snake
class does not explicitly define a constructor. Nevertheless, when creating a snake object, the consumer has to provide the name
argument that is required by Animal
class.
In Jeff's code the Snake class has a default value for the name
which is achieved by constructor(name: string = 'BeatSSS') { super(name); }
. I don't know your specific use case. If there's no any meaningful default name for the snake, I would avoid declaring such constructor altogether.
Duncan correctly explains that calling super()
is not inherently wrong. Moreover, it is necessary.
When an object of type Snake
is being created by the means of its constructor, the parent (Animal
's ) constructor has to complete first. Therefore, there is no way for Animal
constructor to "see" the effects of field initialization that happens in the child (Snake
's) constructor. That is impossible due to the order of constructor invocations.
Thus, the only option for the child type to pass the information for parent's constructor is to call super(...)
directly.
super()
call on childconstruct()
solve the problem, but I need do it on every child. Not very elegant solution.
Basically not defining a child constructor altogether is the answer. If your children class have to have the constructors they will force you to invoke super()
as the very first instruction.
using a timeout on parent construct logs the correct value, but is not possible use the instance of class immediately (beacouse timeout is not executed yet).
This is a very bad option. First, it's generally not recommended to have any asynchronous code invocations in constructor.
Second, if you still do a setTimeout(() => this.fixMyState(), 0)
in Animal
constructor it results in a bad effect: immediately after object construction, the object is in a bad state. What if some code uses that object immediately? The () => this.fixMyState(), 0
will not even have a chance to run for repairing the object. It is a rule of thumb to have an object in a good state immediately after its construction. Otherwise, the constructor should throw
an error so that no code can attempt to operate on the object in a bad state.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With