Sergio Tx
Sergio Tx

Reputation: 3868

Typescript class properties not being initialized

I have the following class:

export abstract class LayerStyle {
    protected configuration: { [key: string]: string };
    protected style: ol.style.Style[];

    constructor(config: { [key: string]: string }) {
        this.configuration = config;
        this.createStyle();
    }

    protected abstract createStyle(): void;

    getStyle() {
        return this.style;
    }
}

And its child class:

import { LayerStyle } from './LayerStyle';

export class PointStyle extends LayerStyle {
    //default values
    FILL_COLOR = 'rgba(255,255,255,0.4)';
    STROKE_COLOR = '#3399CC';
    STROKE_WIDTH = 1.25;
    RADIUS = 5;

    createStyle() {
        let fillColor = this.FILL_COLOR;
        let strokeColor = this.STROKE_COLOR;
        let strokeWidth = this.STROKE_WIDTH;
        let radius = this.RADIUS;
        ...
    }
}

When I create a new PointStyle let style = new PointStyle(styles).getStyle(); it says all the class variables (this.FILL_COLOR,this.STROKE_COLOR,this.STROKE_WIDTH,this.RADIUS) are null inside createStyle(). Why? Shouldn't it create the class with its properties? Should I initialize them in the child constructor and then call the parent with super()?

Upvotes: 2

Views: 1427

Answers (1)

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 250326

The problem is the order of execution. Field initializers are just syntactic sugar for fields assigned in the constructor, but the first statement executed in a constructor is the base constructor. If we look at generated code the problem becomes more clear:

var PointStyle = /** @class */ (function (_super) {
    __extends(PointStyle, _super);
    function PointStyle() {
        // Super executed here !
        var _this = _super !== null && _super.apply(this, arguments) || this;
        //Field initialization here after createStyle is executed!
        _this.FILL_COLOR = 'rgba(255,255,255,0.4)';
        _this.STROKE_COLOR = '#3399CC';
        _this.STROKE_WIDTH = 1.25;
        _this.RADIUS = 5;
        return _this;
    }
    ...
    return PointStyle;
}(LayerStyle));
exports.PointStyle = P

Calling members that should be overwritten in constructors is generally a bad idea exactly because of this kind of issue, you should call createStyle in the derived type or add a parameter that suppresses execution of createStyle is called from a derived class:

export abstract class LayerStyle {
    protected configuration: { [key: string]: string };
    protected style: ol.style.Style[];

    constructor(config: { [key: string]: string }, callInit: boolean = true) {
        this.configuration = config;
        if(!callInit) this.createStyle();
    }

    protected abstract createStyle(): void;

    getStyle() {
        return this.style;
    }
}

export class PointStyle extends LayerStyle {
    constructor(config: { [key: string]: string }, callInit: boolean = true) {
        super(config, false);
        if(callInit) this.createStyle();
    }
    //default values
    FILL_COLOR = 'rgba(255,255,255,0.4)';
    STROKE_COLOR = '#3399CC';
    STROKE_WIDTH = 1.25;
    RADIUS = 5;

    createStyle() {
        let fillColor = this.FILL_COLOR;
        let strokeColor = this.STROKE_COLOR;
        let strokeWidth = this.STROKE_WIDTH;
        let radius = this.RADIUS;
    }
}

Upvotes: 1

Related Questions