Reputation: 2672
I want to create a base class with initial data like below:
export abstract class Entity {
constructor(data?) {
if (data) {
Object.assign(this, data);
}
}
}
with a child class like below:
export class Filter extends Entity{
show = true
constructor(filter?: Partial<Filter>) {
super(filter);
}
}
The issue I am facing is that when I create an object like this new Filter({show:false})
, I get the following result:
Filter {show: true}
The object in base class did not reflect the values in child class. Any thoughts why is this happening?
Upvotes: 6
Views: 1317
Reputation: 19
I solved by adding a setTimeOut on the Object.assing like this:
constructor (data) {
setTimeout(() => {
Object.assing(this, data)
}, 0)
}
It makes the assing at the finish of the javascript queue. Or you can make a class decorator and do your logic overriding the constructor
function DecoratorName () {
return function _DecoratorName<T extends {new (...args: any[]): {}}>(constr: T) {
return class extends constr {
constructor (...args: any[]) {
// The logic inside here executes after child declaration
// and allows get no undefined on properties on
// Object.assing use
super(...args)
Object.assign(this, args[0].data)
}
}
}
}
@DecoratorName()
class Example {
}
Upvotes: -1
Reputation: 7446
This happens because, once the code is transpiled, the child class property assignment happens after the parent constructor has been invoked, you can see that by using the typescript playground and set, in the options, to target ES5
.
To make it shorter, the transpiled code will be the following:
"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 __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
var Entity = /** @class */ (function () {
function Entity(data) {
if (data) {
Object.assign(this, data);
}
}
return Entity;
}());
exports.Entity = Entity;
var Filter = /** @class */ (function (_super) {
__extends(Filter, _super);
function Filter(filter) {
var _this = _super.call(this, filter) || this;
_this.show = true;
return _this;
}
return Filter;
}(Entity));
exports.Filter = Filter;
new Filter({ show: false });
As you can see, the relevant part is that, in the Filter's contructor, the show
property is assigned after the parent constructor has been executed.
var Filter = /** @class */ (function (_super) {
__extends(Filter, _super);
function Filter(filter) {
var _this = _super.call(this, filter) || this;
_this.show = true;
return _this;
}
return Filter;
}(Entity));
To solve the issue, you should just redesign your code and make sure you assign the property in the constructor, instead in the class declaration, leaving the class declaration empty:
export abstract class Entity {
constructor(data?) {
if (data) {
Object.assign(this, data);
}
}
}
export class Filter extends Entity{
public show: boolean;
constructor(filter?: Partial<Filter>) {
super(filter);
this.show = (this.show === undefined) ? true : this.show;
console.log(this);
}
}
new Filter({show:false}); // show is false
new Filter(); // show is true (default value)
Working code: https://stackblitz.com/edit/typescript-c4u557
Another possible approach is that Entity
class should have a show
property with a default value, but it doesn't seems like you want do that, from the hierarchy you've shown.
Upvotes: 8
Reputation: 38174
It happens because you've set show
variable to true
in your derived class. So it overrides the value of base class. To avoid this behavior you should just delete initialization value:
export class Filter extends Entity{
show;
constructor(filter?: Partial<Filter>) {
super(filter);
console.log('Filter', this)
}
}
Upvotes: 0